实验1:解决订票终端的临界区管理
订票终端是解决冲突问题,所以信号量的值是1
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <semaphore.h> int ticketAmout = 2; // 票的数量: 全局变量 sem_t mutex; // 定义信号量mutex void* ticketAgent(void* arg){ sem_wait(&mutex); // 执行P操作 int t = ticketAmout; if (t > 0){ printf("One ticket sold\n"); t--; }else{ printf("Ticket sold out\n"); } ticketAmout = t; sem_post(&mutex); // 执行V操作 pthread_exit(0); } int main(int argc, char const* agrv[]){ pthread_t ticketAgent_tid[2]; sem_init(&mutex, 0, 1); // 初始化信号量 for(int i = 0; i < 2; i++){ pthread_create(ticketAgent_tid+i, NULL, ticketAgent, NULL); } for (int i = 0; i < 2; i++){ pthread_join(ticketAgent_tid[i], NULL); } sleep(1); printf("The left ticket is %d\n", ticketAmout); sem_destroy(&mutex); // 销毁信号量 return 0; }
不进行V操作,造成死锁
第二个进程无限busy waiting。
实验2:一般信号量观察
我们现在有5个线程,但是只有两份资源可用;我们通过信号量去模拟这一种情况,将信号量的值初始化为2
我们先来看一种情况,当没有信号量进行控制的时候
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <semaphore.h> void* cars(void* argc){ printf("(%lu) I INTEND to pass the fork\n",pthread_self()); sleep(1); printf("(%lu) I am AT the fork\n",pthread_self()); sleep(1); printf("(%lu) I have PASSED the fork\n",pthread_self()); sleep(1); pthread_exit(0); } int main(int argc, char const* agrv[]){ pthread_t tid[5]; for (int i = 0; i < 5; i++){ pthread_create(tid+i, NULL, cars, NULL); } for (int i = 0; i < 5; i++){ pthread_join(tid[i], NULL); } return 0; }
可以看到每五个进程都同时占用了临界区的通道,也就是临界区同时运行了五个进程,这个是有问题的
我们梳理一下逻辑,input是进入程序,at fork 和 passed fork是分支产生(冲突或者同步),所以at 和 passed这段区域是临界区,代码如下:
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <semaphore.h> sem_t road; void* cars(void* argc){ printf("(%u) I INTEND to pass the fork\n",pthread_self()); sleep(1); sem_wait(&road); // 执行P操作 printf("(%u) I am AT the fork\n",pthread_self()); sleep(1); printf("(%u) I have PASSED the fork\n",pthread_self()); sleep(1); sem_post(&road); // 执行V操作 pthread_exit(0); } int main(int argc, char const* agrv[]){ pthread_t tid[5]; sem_init(&road, 0, 2); for (int i = 0; i < 5; i++){ pthread_create(tid+i, NULL, cars, NULL); } for (int i = 0; i < 5; i++){ pthread_join(tid[i], NULL); } sem_destroy(&road); return 0; }
每个fork执行流一次可以跑两个分支,两分支同步。
同一时间段内只有两个能进入到fork里面,执行完成只有,另外两个才能进入。