多线程2
同步
作用
让多个执行流在访问临界资源的时候是合理访问
条件变量及其接口
本质是:一个PCB等待队列
条件变量 = PCB等待队列 + 一堆接口
PCB等待队列:当线程发现资源不可用的时候,调用变量接口将自己放到PCB等待队列,等待被唤醒
条件变量的类型:pthread_cond_t
初始化
静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
动态初始化
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
cond:待要初始化的“条件变量”的变量
一般情况下,传递一个pthread_cond_t类型变量的地址
attr:一般情况下直接给NULL,采用默认属性
等待接口
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
cond:条件变量
mutex:互斥锁
作用:如果一个执行流调用了该接口,就会将执行流对应的PCB放到参数cond的PCB等待队列当中
唤醒接口
int pthread_cond_signal(pthread_cond_t *cond);
作用:通知(唤醒)PCB等待队列当中的线程,如果被通知的线程接收到了,则从PCB等待队列当中出队操作,正常执行代码
注意:至少唤醒一个PCB等待队列当中的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
作用:同signal一致
注意:唤醒所有PCB等待队列当中的线程
销毁接口
int pthread_cond_destroy(pthread_cond_t *cond);
销毁动态初始化的条件变量
代码实现
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <pthread.h>
4
5 int g_bowl = 1;
6
7 pthread_mutex_t g_lock;
8
9 //eat
W> 10 void* MyThreadA(void* arg)
11 {
12 while(1)
13 {
14 pthread_mutex_lock(&g_lock);
W> 15 printf("i eat %d, i am %p\n", g_bowl, pthread_self());
16 g_bowl--;
17 pthread_mutex_unlock(&g_lock);
18 }
19 return NULL;
20 }
21
22 //make
W> 23 void* MyThreadB(void* arg)
24 {
25 while(1)
26 {
27 pthread_mutex_lock(&g_lock);
28 g_bowl++;
W> 29 printf("i make %d, i am %p\n", g_bowl, pthread_self());
30 pthread_mutex_unlock(&g_lock);
31 }
32 return NULL;
33 }
34
35 int main()
36 {
37 pthread_mutex_init(&g_lock, NULL);
38 pthread_t tid_A, tid_B;
39 pthread_create(&tid_A, NULL, MyThreadA, NULL);
40 pthread_create(&tid_B, NULL, MyThreadB, NULL);
41
42 pthread_join(tid_A, NULL);
43 pthread_join(tid_B, NULL);
44
45 pthread_mutex_destroy(&g_lock);
46 return 0;
47 }
这是一个吃面和做面的代码,一个工作线程A代表吃面的人,一个工作线程B代表做面的人,运行一下
好家伙都吃到负数去了,修改一下
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <pthread.h>
4 #include <stdlib.h>
5
6 #define THREAD_NUM 1//创建一个宏,后边修改宏即可
7
8 int g_bowl = 1;
9 pthread_mutex_t g_lock;
10 pthread_cond_t g_cond;//定义变量
11
12 //eat
W> 13 void* MyThreadA(void* arg)
14 {
15 while(1)
16 {
17 pthread_mutex_lock(&g_lock);
18 //加完锁后需要判断是否能够吃
19 //没有面则等待,有则吃
20 if(g_bowl < 1)//没有面的情况
21 {
22 //等待
23 pthread_cond_wait(&g_cond, &g_lock);
24 }
25 //有面吃就打印
W> 26 printf("i eat %d, i am %p\n", g_bowl, pthread_self());
27 g_bowl--;
28 pthread_mutex_unlock(&g_lock);
29 //吃完面后通知(唤醒)做面的人
30 pthread_cond_signal(&g_cond);
31 }
32 return NULL;
33 }
34
35 //make
W> 36 void* MyThreadB(void* arg)
37 {
38 while(1)
39 {
40 pthread_mutex_lock(&g_lock);
41 //加完锁后需要判断是否继续做
42 //有面则等待,没面做面
43 if(g_bowl >= 1)//有面的情况
44 {
45 //等待
46 pthread_cond_wait(&g_cond, &g_lock);
47 }
48 //没有面进入下一步做面
49 g_bowl++;
W> 50 printf("i make %d, i am %p\n", g_bowl, pthread_self());
51 pthread_mutex_unlock(&g_lock);
52 //通知吃面
53 pthread_cond_signal(&g_cond);
54 }
55 return NULL;
56 }
57
58 int main()
59 {
60 pthread_mutex_init(&g_lock, NULL);
61
62 pthread_cond_init(&g_cond, NULL);//初始化
63
64 pthread_t tid_A[THREAD_NUM], tid_B[THREAD_NUM];
65 for(int i = 0; i < THREAD_NUM; i++)
66 {
67 int ret = pthread_create(&tid_A[i], NULL, MyThreadA, NULL);
68 if(ret <