[OS:TEP] 代码 自用

That there's some good in this world, and it's worth fighting for.

//1st

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void test1();

void test2();

int main(int argc, char *argv[])    //参数由操作系统传递,argc代表参数的个数,argv[]为指向参数的指针的数组
{
    if (argc == 1) 
    {
        test1();
    } else 
    {
        test2();
    }
    return 0;
}

void test1() 
{
    int pid = fork();      //创建子进程
    int x = 100;
    if (pid < 0) 
    {
        printf("fork error\n");
        exit(1);
    } else if (pid == 0)    //子进程的pid=0
    {
        printf("child, x %d\n", x);
    } else 
    {
        printf("parent, x %d\n", x);
    }
}

void test2() {
    int pid = fork();
    int x = 100;
    if (pid < 0) 
    {
        printf("fork error\n");
        exit(1);
    } else if (pid == 0) 
    {
        printf("child,x %d\n", x);
        x = 0;
        printf("child,x %d\n", x);
    } else 
    {
        printf("parent,x %d\n", x);
        x = 1;
        printf("parent,x %d\n", x);
    }
}
//parent,x 100
//parent,x 1
//child,x 100
//child,x 0




//2ed
#define _GNU_SOURCE //sched_setaffinity

#include "sched.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sys/time.h"
#include "unistd.h"


int main() {
    int fd1[2], fd2[2], fdt[2], pid, n;
    char buffer[1];

    struct timeval tv_bg, tv_end;   //timeval=timevalue
    const struct sched_param param = {sched_get_priority_min(SCHED_FIFO)};
    cpu_set_t set;
    // 将cpu 0 添加到集合
    CPU_SET(0, &set);

    printf("输入测试次数(次数太少会导致误差极大): ");
    scanf("%d", &n);

    if (pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(fdt) < 0) {
        perror("pipe");
        exit(EXIT_FAILURE);
    };

    if ((pid = fork()) < 0) {
        printf("error");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // 需要root 权限
        // SCHED_FIFO指定先来先服务调度,
        if (sched_setscheduler(getpid(), SCHED_FIFO, &param) == -1) {
            printf("程序运行需要root权限(sched_setscheduler系统调用)\n");
            perror("sched_setscheduler");
            exit(EXIT_FAILURE);
        }

        // 线程绑定核心
        if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &set) == -1) {
            perror("sched_setaffinity");
            exit(EXIT_FAILURE);
        }


        gettimeofday(&tv_bg, NULL);
        for (int i = 0; i < n; i++) {
            read(fd1[0], buffer, NULL);
            write(fd2[1], "h", 1);
        }

        write(fdt[1], &tv_bg, sizeof(tv_bg));
        exit(EXIT_SUCCESS);

    } else {
        if (sched_setscheduler(getpid(), SCHED_FIFO, &param) == -1) {
            perror("sched_setscheduler");
            exit(EXIT_FAILURE);
        }

        if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &set) == -1) {
            perror("sched_setaffinity");
            exit(EXIT_FAILURE);
        }

        for (int i = 0; i < n; i++) {
            write(fd1[1], "h", 1);
            read(fd2[0], buffer, NULL);
        }
        gettimeofday(&tv_end, NULL);

        read(fdt[0], &tv_bg, sizeof(tv_bg));

        printf("上下文切换时间为: %f 微秒",
               (float) (tv_end.tv_sec * 1000000 + tv_end.tv_usec - tv_bg.tv_sec * 1000000 - tv_bg.tv_usec) / 2 / n);
    }
    return 0;
}




//3rd
#include <stdio.h>
#include <sys/time.h>   //关于时间的库
#include <unistd.h>

int main() {
    int n;
    printf("输入运行系统调用次数: ");
    scanf("%d", &n);

    struct timeval tv_begin, tv_end;
    gettimeofday(&tv_begin, NULL);  //第二个参数弃用
    for (int i = 0; i < n; i++) {
        read(0, NULL, 0);           //个程序中的 read() 调用传入了长度为 0 的缓冲区,相当于不读取任何数据,只是简单地从标准输入中清空已有的数据
    }
    gettimeofday(&tv_end, NULL);
    printf("执行时间为: %f微秒",(float )(tv_end.tv_sec * 1000000 + tv_end.tv_usec - tv_begin.tv_sec * 1000000 - tv_begin.tv_usec) / n);
    return 0;
}

void comment(void)
{
    struct timeval 
    {
        time_t tv_sec;      /* 秒数 */
        suseconds_t tv_usec;  /* 微秒数 */
        //成员变量 tv_sec 的注释为 "seconds",表示从 1970 年 1 月 1 日 00:00:00 开始到当前时间经过的秒数;
        //成员变量 tv_usec 的注释为 "microseconds",表示从上一秒的开始时间到当前时间之间经过的微秒数。
    };
}




//4th
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <assert.h>
#include "unistd.h"


// 第一个参数为分配内存空间大小,第二个参数为运行的时间(秒)
int main(int argc, char *argv[])
{
    // 检查命令行参数数量是否正确
    if (argc != 3)
    {
        exit(EXIT_FAILURE);
    }

    struct timeval tv_begin, now;

    // 解析内存大小和运行时长参数
    int memory = atoi(argv[1]) * 1024 * 1024; // 以 MB 为单位
    int runtime = atoi(argv[2]); // 以秒为单位

    // 计算数组长度
    int length = memory / 4;    //int占4bit

    // 分配动态数组内存
    int *arr = malloc(4 * length);
    assert(arr != NULL);

    // 输出当前进程的进程ID
    printf("pid: %d\n", getpid());

    // 获取起始时间
    gettimeofday(&tv_begin, NULL);

    // 在规定的运行时长内执行循环
    while (1)           //自旋
    {
        // 获取当前时间
        gettimeofday(&now, NULL);

        // 检查是否达到运行时长
        if (now.tv_sec - tv_begin.tv_sec >= runtime)
        {
            break;
        }

        // 写入数据到数组
        for (int i = 0; i < length; i++)
        {
            arr[i] = i;
        }
    }

    // 释放动态数组内存
    free(arr);

    return 0;
}



void comment(void)
{
    //unistd库
    #include <unistd.h>

    // 从文件描述符 fd 中读取 count 个字节的数据到 buf 中,并返回实际读取到的字节数。
    ssize_t read(int fd, void *buf, size_t count);

    // 将 buf 中的 count 个字节数据写入到文件描述符 fd 对应的文件中,并返回实际写入的字节数。
    ssize_t write(int fd, const void *buf, size_t count);

    // 检查进程对指定路径名 pathname 对应文件是否具有指定的权限 mode,若有则返回 0,否则返回 -1 并设置 errno 错误码。
    int access(const char *pathname, int mode);

    // 创建一个管道,其中 pipefd[0] 为读端文件描述符,pipefd[1] 为写端文件描述符。
    int pipe(int pipefd[2]);

    // 创建一个子进程,子进程是父进程的副本,从调用 fork() 开始,分别在子进程和父进程中返回不同的值(子进程返回 0)以区分两个进程,并继承父进程的数据空间、堆和栈等资源,但它们拥有各自独立的内存空间和虚拟地址空间。
    pid_t fork(void);

    // 使当前进程睡眠指定秒数 seconds,如果在这段时间内被某个信号唤醒,则返回剩下的秒数;否则返回 0。
    unsigned int sleep(unsigned int seconds);

    // 重新设置文件偏移量,函数成功时返回新的偏移量,错误时返回 -1 并设置 errno 错误码;
    off_t lseek(int fd, off_t offset, int whence);

    // 关闭文件描述符 fd 指向的文件,成功时返回 0,错误时返回 -1 并设置 errno 错误码。
    int close(int fd);


    //atoi函数
    #include <stdio.h>
    #include <stdlib.h>

    const char *str = "12345";

    // 使用 atoi 函数将字符串转换为整数
    int value = atoi(str);

    // 打印原始字符串和转换后的整数值
    printf("String: %s\n", str);            //str="12345"
    printf("Integer value: %d\n", value);   //value=12345

    return 0;
}




//5th
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>

#define INIT_SIZE 10
#define EXTEND_SIZE 2000
#define LOOPS 100000000
#define RETIME 100

typedef struct Vector
{
    int *x;            // 存储 x 坐标的数组
    int *y;            // 存储 y 坐标的数组
    int length;          // 当前元素个数
    int max_length;      // 数组的最大容量
} Vector;

// 向 Vector 中追加坐标点
int v_append(Vector *v, int x, int y);

// 释放 Vector 内存
void v_free(Vector *v);


int main()
{
    struct timeval tv_bg, tv_end; 
    Vector v = 
    {
        .length = 0,
        .max_length = INIT_SIZE,
        .x = (int *) malloc(sizeof(int) * INIT_SIZE),
        .y = (int *) malloc(sizeof(int) * INIT_SIZE)
    };

    for(int i = 1;i <= LOOPS;i++)
    {
        gettimeofday(&tv_bg,NULL);
        v_append(&v, i%2048, (i+1)%2048);
        gettimeofday(&tv_end,NULL);
        long long time_diff = (tv_end.tv_sec * 1000000 + tv_end.tv_usec - tv_bg.tv_sec * 1000000 - tv_bg.tv_usec);
        if(time_diff >= RETIME)
            printf("创建此第%d\t个向量:(%d,%d)\t花费时间为: %lld\t微秒\n", i, v.x[i-1], v.y[i-1],time_diff);
    }

    v_free(&v);
    return 0;
}


// 向 Vector 中追加坐标点
int v_append(Vector *v, int x, int y)
{
    // 检查是否需要扩展数组容量
    if (v->length + 1 >= v->max_length)
    {   
        v->max_length += EXTEND_SIZE;
        v->x = (int *) realloc(v->x, sizeof(int) * v->max_length);
        v->y = (int *) realloc(v->y, sizeof(int) * v->max_length);
    }

    // 将坐标点添加到数组末尾
    v->x[v->length] = x;
    v->y[v->length] = y;
    v->length += 1;

    return v->length;
}

// 释放 Vector 内存
void v_free(Vector *v)
{
    free(v->x);
    free(v->y);
}


void comment(void)
{
    #include <stdlib.h>

    /**
     * @brief 重新分配内存空间的函数
     * 
     * @param ptr 指向要重新分配内存空间的指针
     * @param size 新的大小
     * @return void* 指向重新分配后的内存空间的指针,或者在分配失败时返回NULL
     */
    void *realloc(void *ptr, size_t size);
    /**
     *  realloc函数的作用是重新分配内存空间,可以用于扩大或缩小已分配内存块的大小。它的行为如下:
     *
     *  如果ptr是NULL,则realloc的行为与malloc(size)相同,即分配一个新的内存块并返回指向它的指针。
     *  如果ptr不是NULL,则realloc会尝试将已分配内存块的大小调整为size。它可能有以下几种情况:
     *  如果size为0,那么realloc的行为与free(ptr)相同,即释放该内存块,并返回NULL。
     *  如果size大于已分配内存块的大小,realloc会尝试在原地扩大该内存块,如果扩大成功,则返回指向扩大后内存块的指针;
     *  如果扩大失败,则会分配一个新的内存块,并将原内存块的内容复制到新内存块中,然后释放原内存块,并返回指向新内存块的指针。
     *  如果size小于或等于已分配内存块的大小,realloc会尝试在原地缩小该内存块,如果缩小成功,则返回指向缩小后内存块的指针;
     *  如果缩小失败,则会分配一个新的内存块,将原内存块的内容复制到新内存块中,然后释放原内存块,并返回指向新内存块的指针。
     *  需要注意的是,realloc函数可能会在重新分配内存空间时进行复制操作,因此在性能要求较高的情况下,应尽量避免频繁地调用realloc函数。
     *  此外,对于使用realloc函数重新分配内存空间后返回的指针,应该将其赋值给原来的指针变量,以防止内存泄漏。
     **/
}




//6th
#define _GNU_SOURCE //sched_setaffinity
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>

#define PAGESIZE 4096

int main(int argc, char *argv[])
{
    int nLoop = 10, nPages = 10;
    int opt;

    if (argc == 5)
    {
        while ((opt = getopt(argc, argv, "l:p:")) != -1)
        {
            switch (opt)
            {
                case 'l':
                    nLoop = atoi(optarg);
                    break;
                case 'p':
                    nPages = atoi(optarg);
                    break;
            }
        }
    }

    int jump = PAGESIZE / sizeof(int);
    int *a = (int *)malloc(nPages * jump * sizeof(int));

    cpu_set_t set;
    // 将cpu 0 添加到集合
    CPU_SET(0, &set);
    // 绑定cpu核心
    if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &set) == -1)     //将该进程亲和于CPU集,减少进程切换到其他CPU的可能
    {
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }

    uint64_t start, end;
    unsigned cycles_low, cycles_high, cycles_low1, cycles_high1;
    asm volatile 
    (
        "CPUID\n\t"         //这就是C代码内嵌ASM吗!震惊我一百年!
        "RDTSC\n\t"
        "mov %%edx, %0\n\t"
        "mov %%eax, %1\n\t"
        : "=r" (cycles_high), "=r" (cycles_low)
        ::
        "%rax", "%rbx", "%rcx", "%rdx"
    );

    for (int j = 0; j < nLoop; j++)
    {
        for (int i = 0; i < nPages * jump; i += jump)
        {
            a[i] += 1;
        }
    }

    asm volatile (
        "RDTSCP\n\t"
        "mov %%edx, %0\n\t"
        "mov %%eax, %1\n\t"
        "CPUID\n\t"
        : "=r" (cycles_high1), "=r" (cycles_low1)
        ::
        "%rax", "%rbx", "%rcx", "%rdx"
    );

    start = (((uint64_t) cycles_high << 32) | cycles_low);
    end = (((uint64_t) cycles_high1 << 32) | cycles_low1);
    printf("time: %f clock cycles, page: %d\n", (float) (end - start) / (nLoop * nPages), nPages);

    return 0;
}

void comment(void)
{

    // #define _GNU_SOURCE //sched_setaffinity:这是一个预处理指令,用于定义宏并注释关于sched_setaffinity的说明。

    // #include <stdio.h>:包含标准输入输出函数的头文件。

    // #include <stdint.h>:包含定义了标准整数类型的头文件。

    // #include <stdlib.h>:包含标准库函数的头文件。

    // #include <unistd.h>:包含与系统调用相关的函数的头文件。

    // #include <sched.h>:包含与调度相关的函数的头文件。

    // #define PAGESIZE 4096:定义一个宏常量PAGESIZE,表示页面的大小为4096字节。

    // int main(int argc, char *argv[]):程序的入口函数。

    // int nLoop = 10, nPages = 10;:定义并初始化两个整型变量nLoop和nPages,分别表示循环次数和页面数量。

    // int opt;:定义一个整型变量opt,用于存储命令行参数解析的结果。

    // if (argc == 5):检查命令行参数数量是否为5。

    // while ((opt = getopt(argc, argv, "l:p:")) != -1):循环解析命令行参数,通过getopt函数获取命令行选项的值。

    // switch (opt):根据选项值进行分支处理。

    // case 'l': nLoop = atoi(optarg); break;:如果选项为'l',将选项参数转换为整型并赋值给nLoop。

    // case 'p': nPages = atoi(optarg); break;:如果选项为'p',将选项参数转换为整型并赋值给nPages。

    // int jump = PAGESIZE / sizeof(int);:根据页面大小计算出每个页面的元素数量。

    // int *a = (int *) malloc(nPages * jump * sizeof(int));:使用malloc动态分配内存,存储nPages * jump个整型元素。

    // cpu_set_t set;:定义一个cpu_set_t类型的变量set,用于表示CPU集合。

    // CPU_SET(0, &set);:将CPU 0添加到CPU集合中。

    // if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &set) == -1):调用sched_setaffinity函数将进程绑定到指定的CPU核心。

    // uint64_t start, end;:定义两个64位无符号整型变量start和end,用于存储计时器的值。

    // unsigned cycles_low, cycles_high, cycles_low1, cycles_high1;:定义四个无符号整型变量,用于存储计时器的低位和高位值。

    // asm volatile ("CPUID\n\t" "RDTSC\n\t" "mov %%edx, %0\n\t" "mov %%eax, %1\n\t": "=r" (cycles_high), "=r" (cycles_low):: "%rax", "%rbx", "%rcx", "%rdx");:使用内嵌汇编语句执行CPUID和RDTSC指令,获取计时器的值。

    // for (int j = 0; j < nLoop; j++) { for (int i = 0; i < nPages * jump; i += jump) { a[i] += 1; } }:嵌套循环,对数组a进行递增操作。

    // asm volatile("RDTSCP\n\t" "mov %%edx, %0\n\t" "mov %%eax, %1\n\t" "CPUID\n\t": "=r" (cycles_high1), "=r" (cycles_low1):: "%rax", "%rbx", "%rcx", "%rdx");:使用内嵌汇编语句执行RDTSCP和CPUID指令,获取计时器的值。

    // start = (((uint64_t) cycles_high << 32) | cycles_low);:将计时器的高位和低位值合并为64位整数,赋值给start。

    // end = (((uint64_t) cycles_high1 << 32) | cycles_low1);:将计时器的高位和低位值合并为64位整数,赋值给end。

    // printf("time: %f clock cycles, page: %d\n", (float) (end - start) / (nLoop * nPages), nPages);:打印输出所需的时钟周期数和页面数量。

    // return 0;:返回程序执行成功的标志。
}




//7th
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <unistd.h>

#define SLEEPTIME 5

// 获取绝对时间的简单函数(以秒为单位)。
double Time_GetSeconds()
{
    struct timeval t;
    int rc = gettimeofday(&t, NULL);
    assert(rc == 0);
    return (double)((double)t.tv_sec + (double)t.tv_usec / 1e6);
}

// 分配一定大小的整型数组,并在循环中不断更新每个整数的值。
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "用法: spin <内存大小(MB)>\n");
        exit(1);
    }

    long long int size = (long long int)atoi(argv[1]);
    long long int size_in_bytes = size * 1024 * 1024;       //需求内存大小的x MB = x * 1024 KB = x * 1024 * 1024 B

    printf("正在分配 %lld 字节(%.2f MB)的内存\n", size_in_bytes, size_in_bytes / (1024 * 1024.0));

    // 实际的内存分配发生在这里
    int *x = malloc(size_in_bytes);
    if (x == NULL)
    {
        fprintf(stderr, "内存分配失败\n");
        exit(1);
    }

    long long int num_ints = size_in_bytes / sizeof(int);
    printf("数组中的整数数量:%lld\n", num_ints);

    sleep(SLEEPTIME);

    // 主循环:每次循环遍历数组并将每个整数加1
    int i = 0;
    double time_since_last_print = 2.0;
    double t = Time_GetSeconds();
    int loop_count = 0;

    while (1)
    {
        x[i++] += 1; // 主要工作在这里完成。

        // 如果已经遍历整个数组,重置一些变量并(可能)打印一些统计信息。
        if (i == num_ints)
        {
            double delta_time = Time_GetSeconds() - t;
            time_since_last_print += delta_time;

            if (time_since_last_print >= 0.2) // 每0.2秒打印一次
            {
                printf("第 %d 轮循环耗时:%.2f 毫秒(带宽:%.2f MB/s)\n",
                       loop_count, 
                       1000 * delta_time,
                       (size_in_bytes / 1024.0 * 1024.0) / delta_time);
                time_since_last_print = 0;
            }

            i = 0;
            t = Time_GetSeconds();
            loop_count++;
        }
    }

    return 0;
}




8th
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;     //锁不仅要声明,还要初始化!
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;

void* worker(void* arg)                             //我深深地爱着ChatGPT!!! 
{
    if ((long long) arg == 0) 
    {
        printf("Thread 1: Acquiring lock m1...\n"); //死锁的很漂亮!
        pthread_mutex_lock(&m1);
        sleep(5);                                   //由于在并发之中,p1获得m1时或p2获得m2睡了5s,导致对方必然抢夺锁胜利,由此死锁必然成功!
        printf("Thread 1: Got lock m1!\n");
        printf("Thread 1: Acquiring lock m2...\n");
        pthread_mutex_lock(&m2);
        printf("Thread 1: Got lock m2!\n");
    } else 
    {
        printf("Thread 2: Acquiring lock m2...\n");
        pthread_mutex_lock(&m2);
        sleep(5);   
        printf("Thread 2: Got lock m2!\n");
        printf("Thread 2: Acquiring lock m1...\n");
        pthread_mutex_lock(&m1);
        printf("Thread 2: Got lock m1!\n");
    }
    pthread_mutex_unlock(&m1);      // 解锁互斥锁 m1
    pthread_mutex_unlock(&m2);      // 解锁互斥锁 m2
    return NULL;
}

int main(int argc, char *argv[]) 
{
    pthread_t p1, p2;
    pthread_create(&p1, NULL, worker, (void *) (long long) 0);    // 创建线程 p1,执行 worker 函数,参数为 0
    pthread_create(&p2, NULL, worker, (void *) (long long) 1);    // 创建线程 p2,执行 worker 函数,参数为 1
    pthread_join(p1, NULL);    // 主线程等待线程 p1 结束
    pthread_join(p2, NULL);    // 主线程等待线程 p2 结束
    return 0;
}




//9th
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t g0 = PTHREAD_MUTEX_INITIALIZER;     //全局锁
pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;     //锁不仅要声明,还要初始化!
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;

void* worker(void* arg)                             //我深深地爱着ChatGPT!!! 
{
    pthread_mutex_lock(&g0);
    if ((long long) arg == 0) 
    {
        printf("Thread 1: Acquiring lock m1...\n"); //死锁的很漂亮!
        pthread_mutex_lock(&m1);
        printf("Thread 1: Got lock m1!\n");
        sleep(5);                                     //由于在并发之中,p1获得m1时或p2获得m2睡了5s,导致对方必然抢夺锁胜利,由此死锁必然成功!但是全局锁使之完成m12锁的全部获取与释放!
        printf("Thread 1: Acquiring lock m2...\n");
        pthread_mutex_lock(&m2);
        printf("Thread 1: Got lock m2!\n");
    } else 
    {
        printf("Thread 2: Acquiring lock m2...\n");
        pthread_mutex_lock(&m2);
        printf("Thread 2: Got lock m2!\n");
        sleep(5);   
        printf("Thread 2: Acquiring lock m1...\n");
        pthread_mutex_lock(&m1);
        printf("Thread 2: Got lock m1!\n");
    }
    pthread_mutex_unlock(&m1);      // 解锁互斥锁 m1
    pthread_mutex_unlock(&m2);      // 解锁互斥锁 m2
    pthread_mutex_unlock(&g0);
    return NULL;
}

int main(int argc, char *argv[]) 
{
    pthread_t p1, p2;
    pthread_create(&p1, NULL, worker, (void *) (long long) 0);    // 创建线程 p1,执行 worker 函数,参数为 0
    pthread_create(&p2, NULL, worker, (void *) (long long) 1);    // 创建线程 p2,执行 worker 函数,参数为 1
    pthread_join(p1, NULL);    // 主线程等待线程 p1 结束
    pthread_join(p2, NULL);    // 主线程等待线程 p2 结束

    printf("----->No DeadLock!<-----\n");
    return 0;
}




//10th
#include <stdio.h>
#include <pthread.h>

#define LOOPS 100

int balance = 0;

void* worker(void* arg)
{
    balance++; // 未保护的访问

    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t p;

    // 创建线程并执行 worker 函数
    for(int i = 0; i < LOOPS; i++)
        pthread_create(&p, NULL, worker, NULL);     //这个程序感觉不是很好

    // 未保护的访问,对 balance 进行自增操作
    balance++;

    // 等待线程 p 结束
    pthread_join(p, NULL);

    printf("The Balance is %d", balance);

    return 0;
}




//11th
#include <stdio.h>
#include <pthread.h>

// int done = 0;

void* worker(void* arg)
{
    printf("this should print first\n");
    // done = 1;
    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t p;
    pthread_create(&p, NULL, worker, NULL); // 创建线程 p,执行 worker 函数,参数为 NULL/

    // while (done == 0)       //出现了,自旋君! 我们把这个去掉看看!
    // {                       //实际上,在主线程结束时,子线程也会被迫结束,这是因为主线程是整个程序的主控线程,当主线程结束时,整个程序也会随之结束。
                               //由此实际没有显示worker的,估计是主进程被调度的必然
    //     // 等待 done 变量的值变为 1,以确保线程执行完毕
    // }

    printf("this should print last\n");

    pthread_join(p, NULL);     //等待他的儿子结束

    return 0;
}                               //哈哈,可以了,这个程序应该叫条件变量解决的调度问题




//12th(全th吧!)       //如果没有ChatGPT,那我的世界将黯淡无光!
#include <stdio.h>
#include <pthread.h>

typedef struct __synchronizer_t 
{
    pthread_mutex_t lock;   // 互斥锁
    pthread_cond_t cond;    // 条件变量
    int done;               // 完成标志
} synchronizer_t;

synchronizer_t s;           // 全局同步器对象

// 初始化同步器
void signal_init(synchronizer_t *s)
{
    pthread_mutex_init(&s->lock, NULL);        // 初始化互斥锁
    pthread_cond_init(&s->cond, NULL);         // 初始化条件变量
    s->done = 0;                               // 完成标志初始为0
}

// 完成信号
void signal_done(synchronizer_t *s)
{
    pthread_mutex_lock(&s->lock);               // 加锁
    s->done = 1;                               // 设置完成标志为1
    pthread_cond_signal(&s->cond);              // 发送条件信号,通知等待线程
    pthread_mutex_unlock(&s->lock);             // 解锁
}

// 等待信号
void signal_wait(synchronizer_t *s)
{
    pthread_mutex_lock(&s->lock);               // 加锁
    while (s->done == 0) {                      // 若完成标志为0,则继续等待
        pthread_cond_wait(&s->cond, &s->lock);   // 等待条件信号
    }
    pthread_mutex_unlock(&s->lock);             // 解锁
}

// 工作线程函数
void *worker(void *arg)
{
    printf("This should print first\n");
    signal_done(&s);                            // 发送完成信号
    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t p;
    signal_init(&s);                            // 初始化同步器
    pthread_create(&p, NULL, worker, NULL);      // 创建工作线程
    signal_wait(&s);                            // 等待完成信号   //只有done=1时,才会唤醒!
    printf("This should print last\n");

    return 0;
}




//13th
#include <stdio.h>

#include <pthread.h>

int balance = 0;

void *worker(void *lock) 
{
    pthread_mutex_lock(lock);
    balance++; // unprotected access
    pthread_mutex_unlock(lock);
    return NULL;
}

int main(int argc, char *argv[]) 
{
    pthread_t p;
    pthread_mutex_t lock;
    pthread_mutex_init(&lock, NULL);

    pthread_create(&p, NULL, worker, &lock);

    pthread_mutex_lock(&lock);
    balance++; // unprotected access
    pthread_mutex_unlock(&lock);

    pthread_join(p, NULL);
    return 0;
}














  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值