多任务互斥与同步(互斥锁, 读写锁, 条件变量, 信号量, 命名信号量)

This commit is contained in:
flykhan 2023-08-22 20:46:40 +08:00
parent d1bc1e2410
commit 7d8e55d275
14 changed files with 820 additions and 0 deletions

83
day7/condition.c Normal file
View File

@ -0,0 +1,83 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 条件变量实例
// 互斥锁和条件变量的初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void *producer_task(void *data)
{
int *n = (int *)data;
while (1)
{
pthread_mutex_lock(&mutex);
while (*n == 10) // 只要资源为 10 ,就等待
{
// 条件变量等待后,会自动释放 mutex 锁
pthread_cond_wait(&cond, &mutex);
}
(*n)++;
printf("生产线程(%ld)生产了 %d 个产品\n", pthread_self(), *n);
// 发出通知,让等待消费的线程恢复(条件满足)
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
// usleep(200 * 1000);
sleep(1);
}
pthread_exit(NULL);
}
void *consumer_task(void *data)
{
int *n = (int *)data;
while (1)
{
pthread_mutex_lock(&mutex);
while (*n == 0) // 只要资源为 0 ,就等待
{
// 条件变量等待后,会自动释放 mutex 锁
pthread_cond_wait(&cond, &mutex);
}
printf("消费者(%ld) 消费了 %d 产品\n", pthread_self(), *n);
(*n)--;
pthread_mutex_unlock(&mutex);
// usleep(200 * 1000);
sleep(1);
}
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
int num = 3; // 3 个产品
pthread_t threads[10];
// 创建 2 个生产线程
for (int i = 0; i < 8; i++)
{
pthread_create(&threads[i], NULL, producer_task, &num);
}
// 创建 3 个消费者线程
for (int i = 8; i < 10; i++)
{
pthread_create(&threads[i], NULL, consumer_task, &num);
}
for (int i = 0; i < 10; i++)
{
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}

58
day7/mutex_1.c Normal file
View File

@ -0,0 +1,58 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 定义两把锁
pthread_mutex_t mutex1, mutex2;
void *task1(void *data)
{
char *taskName = (char *)data;
pthread_mutex_lock(&mutex1);
printf("%s 获取锁 1 成功, 等待 1 秒后获取锁 2\n", taskName);
sleep(1);
pthread_mutex_lock(&mutex2);
printf("%s 获取锁 2 成功\n", taskName);
printf("%s\n", taskName);
// 释放锁
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
void *task2(void *data)
{
char *taskName = (char *)data;
pthread_mutex_lock(&mutex1);
printf("%s 获取锁 1 成功, 等待 1 秒后获取锁 2\n", taskName);
sleep(1);
pthread_mutex_lock(&mutex2);
printf("%s 获取锁 2 成功\n", taskName);
printf("%s\n", taskName);
// 释放锁
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
int main(int argc, char const *argv[])
{
// 动态初始化锁
pthread_mutex_init(&mutex1, NULL);
pthread_mutex_init(&mutex2, NULL);
// 创建线程
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, task1, "hello");
pthread_create(&tid2, NULL, task2, "world");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
// 销毁锁
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
return 0;
}

45
day7/named_sem_1.c Normal file
View File

@ -0,0 +1,45 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
// 命名信号实例
void printer(char *msg)
{
while (*msg)
{
printf("%c", *msg++); // 打印字符
fflush(stdout); // 刷新控制台
sleep(1);
}
}
int main(int argc, char const *argv[])
{
// 命名信号
sem_t *sem = sem_open("mysem", O_CREAT | O_RDWR, 0644, 1);
int pid = fork();
if (pid == 0) // 子进程
{
sem_wait(sem);
printer("disen666");
sem_post(sem);
_exit(0);
}
else if (pid > 0) // 父进程
{
sem_wait(sem);
printer("jack888");
sem_post(sem);
wait(NULL); // 等待子进程退出
printf("\n---over---\n");
sem_close(sem); // 关闭信号量
sem_unlink("mysem"); // 删除信号量文件
}
return 0;
}

48
day7/named_sem_2.c Normal file
View File

@ -0,0 +1,48 @@
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
// 命名信号实例
void printer(char *msg)
{
while (*msg)
{
printf("%c", *msg++); // 打印字符
fflush(stdout); // 刷新控制台
sleep(1);
}
}
int main(int argc, char const *argv[])
{
// 命名信号
sem_t *sem1 = sem_open("mysem1", O_CREAT | O_RDWR, 0644, 1);
sem_t *sem2 = sem_open("mysem2", O_CREAT | O_RDWR, 0644, 0);
int pid = fork();
if (pid == 0) // 子进程
{
sem_wait(sem1);
printer("disen666");
sem_post(sem2);
_exit(0);
}
else if (pid > 0) // 父进程
{
sem_wait(sem2);
printer("jack888");
sem_post(sem1);
wait(NULL); // 等待子进程退出
printf("\n---over---\n");
sem_close(sem1); // 关闭信号量
sem_close(sem2); // 关闭信号量
sem_unlink("mysem1"); // 删除信号量文件
sem_unlink("mysem2"); // 删除信号量文件
}
return 0;
}

34
day7/named_sem_3.c Normal file
View File

@ -0,0 +1,34 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
// 无血缘关系的进程的互斥
void printer(char *msg)
{
while (*msg)
{
printf("%c", *msg++);
fflush(stdout);
sleep(1);
}
}
int main(int argc, char const *argv[])
{
// 打开信号量文件
sem_t *sem = sem_open("mysem", O_CREAT | O_RDWR, 0666, 1);
sem_wait(sem);
#ifdef DISEN
printer("disen666\n");
#else
printer("jack888\n");
#endif
sem_post(sem);
sem_close(sem);
return 0;
}

38
day7/named_sem_4.c Normal file
View File

@ -0,0 +1,38 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
// 无血缘关系的进程的同步
void printer(char *msg)
{
while (*msg)
{
printf("%c", *msg++);
fflush(stdout);
sleep(1);
}
}
int main(int argc, char const *argv[])
{
// 打开信号量文件
sem_t *sem1 = sem_open("mysem1", O_CREAT | O_RDWR, 0666, 1);
sem_t *sem2 = sem_open("mysem2", O_CREAT | O_RDWR, 0666, 0);
#ifdef DISEN
sem_wait(sem2);
printer("disen666\n");
sem_post(sem1);
#else
sem_wait(sem1);
printer("jack888\n");
sem_post(sem2);
#endif
sem_close(sem1);
sem_close(sem2);
return 0;
}

28
day7/nomutex.c Normal file
View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void *printer(void *data)
{
char *msg = (char *)data;
while (*msg)
{
printf("%c", *msg++);
fflush(stdout);
sleep(1);
}
return NULL;
}
int main(int argc, char const **argv)
{
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, printer, "disen666\0");
pthread_create(&tid2, NULL, printer, "lucy888\0");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("---over---\n");
return 0;
}

42
day7/nomutex_2.c Normal file
View File

@ -0,0 +1,42 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 静态初始化互斥锁
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 动态初始化锁-定义锁
pthread_mutex_t mutex;
void *printer(void *data)
{
char *msg = (char *)data;
pthread_mutex_lock(&mutex); // 申请上锁,可能阻塞
while (*msg)
{
printf("%c", *msg++);
fflush(stdout);
usleep(200 * 1000);
}
pthread_mutex_unlock(&mutex); // 不解锁,就会发生死锁
return NULL;
}
int main(int argc, char const **argv)
{
// 动态初始化锁-初始化
pthread_mutex_init(&mutex, NULL);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, printer, "disen666\n");
pthread_create(&tid2, NULL, printer, "lucy888\n");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("\n---over---\n");
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}

54
day7/nomutex_3.c Normal file
View File

@ -0,0 +1,54 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 静态初始化互斥锁
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 动态初始化锁-定义锁
pthread_mutex_t mutex;
void *printer(void *data)
{
char *msg = (char *)data;
int lock_acquired = 0; // 未获取到锁
while (!lock_acquired) // 未获取到锁的时候,循环尝试获取锁,并处理
{
// trylock 非阻塞锁
if (pthread_mutex_trylock(&mutex) == 0) // 如果拿到锁
{
lock_acquired = 1; // 该状态:已获取到锁
while (*msg) // 当前线程传入的字符串未读取完成时,循环读取
{
printf("%c", *msg++);
fflush(stdout);
usleep(200 * 1000);
}
pthread_mutex_unlock(&mutex); // 读完后,解锁当前进程
}
else
{
usleep(100); // 0.1 毫秒后继续尝试获取锁
}
}
return NULL;
}
int main(int argc, char const **argv)
{
// 动态初始化锁-初始化
pthread_mutex_init(&mutex, NULL);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, printer, "disen666\n");
pthread_create(&tid2, NULL, printer, "lucy888\n");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("\n---over---\n");
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}

52
day7/rwlock_1.c Normal file
View File

@ -0,0 +1,52 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 定义读写锁(需要 GNU99
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; // 静态初始化读写锁
void *read_task(void *data)
{
int *n = (int *)data;
while (1)
{
pthread_rwlock_rdlock(&rwlock); // 申请读锁 rdlock
printf("(%ld)线程读取 num: %d\n", pthread_self(), *n);
pthread_rwlock_unlock(&rwlock); // 解锁
usleep(500 * 1000);
}
return NULL;
}
void *write_task(void *data)
{
int *n = (int *)data;
while (1)
{
pthread_rwlock_wrlock(&rwlock); // 申请写锁 wrlock
(*n)++;
printf("(%ld) 线程写 num: %d\n", pthread_self(), *n);
pthread_rwlock_unlock(&rwlock); // 解锁
sleep(2);
}
return NULL;
}
int main(int argc, char const *argv[])
{
int num; // 公共资源
pthread_t t1, t2, t3;
pthread_create(&t1, NULL, read_task, &num);
pthread_create(&t2, NULL, read_task, &num);
pthread_create(&t3, NULL, write_task, &num);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_rwlock_destroy(&rwlock); // 销毁读写锁
return 0;
}

97
day7/rwlock_2.c Normal file
View File

@ -0,0 +1,97 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
int money = 1000; // 存款余额
int exit_flag = 0; // 退出标志
void *task1(void *data)
{
while (1)
{
pthread_rwlock_wrlock(&rwlock); // 加写锁
// 查询余额
printf("存款任务-余额: %d\n", money);
usleep(200 * 1000);
// 从键盘读取存入的金额
printf("请输入存款金额 (输入 0 结束存款): ");
fflush(stdout);
int m;
scanf("%d", &m);
if (m == 0)
{
exit_flag = 1;
pthread_rwlock_unlock(&rwlock); // 解锁
break;
}
money += m;
// 修改余额并打印结果
printf("存款成功, 余额为 %d\n", money);
pthread_rwlock_unlock(&rwlock); // 解锁
}
pthread_exit(NULL);
}
void *task2(void *data)
{
while (1)
{
pthread_rwlock_wrlock(&rwlock); // 加写锁
// 查询余额
printf("取款任务-余额: %d\n", money);
usleep(200 * 1000);
// 从键盘读取取出的金额
printf("请输入取款金额 (输入 0 结束取款): ");
fflush(stdout);
int m;
scanf("%d", &m);
if (m == 0)
{
exit_flag = 1;
pthread_rwlock_unlock(&rwlock); // 解锁
break;
}
if (money >= m)
{
money -= m;
// 修改余额并打印结果
printf("取款成功, 余额为 %d\n", money);
}
else
{
printf("取款失败, 余额不足\n");
}
pthread_rwlock_unlock(&rwlock); // 解锁
}
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
while (1)
{
pthread_t t1, t2;
pthread_create(&t1, NULL, task1, NULL);
pthread_create(&t2, NULL, task2, NULL);
while (1)
{
pthread_rwlock_rdlock(&rwlock);
if (exit_flag)
{
pthread_rwlock_unlock(&rwlock);
break;
}
pthread_rwlock_unlock(&rwlock);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}
pthread_rwlock_destroy(&rwlock);
return 0;
}

48
day7/sem_1.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
// 信号量实例
sem_t sem; // 定义信号量
void *printer(void *data)
{
char *msg = (char *)data;
// P 操作
sem_wait(&sem); // 本案例中锁住了控制台
while (*msg)
{
printf("%c", *msg++);
fflush(stdout);
usleep(200 * 1000);
}
// V 操作
sem_post(&sem);
return NULL;
}
int main(int argc, char const **argv)
{
// 信号量初始化
sem_init(&sem, 0, 1);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, printer, "disen666\n");
pthread_create(&tid2, NULL, printer, "lucy888\n");
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("\n---over---\n");
// 销毁信号量
sem_destroy(&sem);
return 0;
}

105
day7/sem_2.c Normal file
View File

@ -0,0 +1,105 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
// 信号量实例 2 - 存取款
sem_t sem; // 定义信号量
int money = 1000; // 存款余额
int exit_flag = 0; // 退出标志
void *task1(void *data)
{
while (1)
{
sem_wait(&sem); // P 操作
// 查询余额
printf("存款任务-余额: %d\n", money);
usleep(200 * 1000);
// 从键盘读取存入的金额
printf("请输入存款金额 (输入 0 结束存款): ");
fflush(stdout);
int m;
scanf("%d", &m);
if (m == 0)
{
exit_flag = 1;
sem_post(&sem); // V 操作
break;
}
money += m;
// 修改余额并打印结果
printf("存款成功, 余额为 %d\n", money);
sem_post(&sem); // V 操作
}
pthread_exit(NULL);
}
void *task2(void *data)
{
while (1)
{
sem_wait(&sem); // P 操作
// 查询余额
printf("取款任务-余额: %d\n", money);
usleep(200 * 1000);
// 从键盘读取取出的金额
printf("请输入取款金额 (输入 0 结束取款): ");
fflush(stdout);
int m;
scanf("%d", &m);
if (m == 0)
{
exit_flag = 1;
sem_post(&sem); // V 操作
break;
}
if (money >= m)
{
money -= m;
// 修改余额并打印结果
printf("取款成功, 余额为 %d\n", money);
}
else
{
printf("取款失败, 余额不足\n");
}
sem_post(&sem); // V 操作
}
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
// 初始化信号量
sem_init(&sem, 0, 1);
while (1)
{
pthread_t t1, t2;
pthread_create(&t1, NULL, task1, NULL);
pthread_create(&t2, NULL, task2, NULL);
while (1)
{
sem_wait(&sem); // P 操作
if (exit_flag)
{
sem_post(&sem); // V 操作
break;
}
sem_post(&sem); // V 操作
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}
// 销毁信号量
sem_destroy(&sem);
return 0;
}

88
day7/sem_3.c Normal file
View File

@ -0,0 +1,88 @@
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
sem_t sem1, sem2; // 信号量
void *task1(void *data)
{
int *money = (int *)data;
// 存款任务
sem_wait(&sem1);
// 查询余额
printf("存款任务-余额: %d\n", *money);
sleep(1);
// 从键盘读取存入的金额
printf("请输入存款金额: ");
fflush(stdout);
int m;
scanf("%d", &m);
*money += m;
// 修改余额并打印结果
printf("存款成功, 余额为: %d\n", *money);
sem_post(&sem2);
pthread_exit(NULL);
}
void *task2(void *data)
{
int *money = (int *)data;
// 取款任务
sem_wait(&sem2);
// 查询余额
printf("取款任务-余额: %d\n", *money);
sleep(1);
// 从键盘读取取出的金额
printf("请输入取款金额: ");
fflush(stdout);
int m;
scanf("%d", &m);
if (*money >= m)
{
*money -= m;
// 修改余额并打印结果
printf("取款成功, 余额为: %d\n", *money);
}
else
{
printf("取款失败,余额不足\n");
}
sem_post(&sem1);
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
// 初始化信号量
sem_init(&sem1, 0, 1); // 存款的信号量初始化
sem_init(&sem2, 0, 0); // 取款的信号量初始化
int money = 1000; // 存款
while (1)
{
printf("输入 exit 退出 , 输入其他内容开始存取款\n");
char input[100];
scanf("%s", input);
if (strncmp(input, "exit", 4) == 0)
{
break;
}
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, task1, &money);
pthread_create(&tid2, NULL, task2, &money);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
}
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}