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, ¶m) == -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, ¶m) == -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;
}