本次笔记记录两个问题:

1,条件变量在使用时会有信号丢失现象;(使用g_nums记录信号,防止信号丢失)

2,条件变量的wait内部锁操作会在惊群现象的时候访问不可用资源,存在潜在的风险;(wait后再次对可用资源进行判断,防止操作不可用资源情况的发生)

在例子代码中都对上面两个现象实现对应的解决方案。

 

 1 #include <iostream>
 2 #include <pthread.h>
 3 #include <unistd.h>
 4 #include <stdio.h>
 5 
 6 pthread_mutex_t mutex;
 7 pthread_cond_t cond;
 8 
 9 int g_nums=0;//如果没有这个计数,条件信号会有部分丢失,即在wait之前发的信号都会丢失
10 
11 void* thread1( void* arg)
12 {
13     while(1)
14     {
15 
16         pthread_mutex_lock(&mutex);
17 
18         if(g_nums <=0 )
19             pthread_cond_wait(&cond, &mutex);
20 
21         //sleep(2);
22         if(g_nums <=0 ){//防止惊群现象,wait后再次lock但另一个线程已经用光了资源,如果不检查就使用会出问题
23             std::cout<<"the thread1 conflict..n";
24             continue;
25         }
26 
27         --g_nums;
28 
29         std::cout<<"the thread1 info: "<<std::endl;
30     
31         pthread_mutex_unlock(&mutex);    
32         sleep(1);
33     }
34 
35     return NULL;
36 }
37 
38 void* thread2(void* arg)
39 {
40 
41     while(true){
42         pthread_mutex_lock(&mutex);
43        
44         if(g_nums <=0)
45             pthread_cond_wait(&cond, &mutex);
46 
47         if(g_nums <= 0){//防止惊群现象,wait后再次lock但另一个线程已经用光了资源,如果不检查就使用会出问题
48             std::cout<<"thread2 conflict...n";
49             continue;
50         }
51         --g_nums;
52 
53         std::cout<<"the thread2 info: "<<std::endl;
54 
55         pthread_mutex_unlock(&mutex);
56 
57         sleep(1);
58     }
59 
60     return NULL;
61 }
62 
63 
64 int main( int argc, char*argv[] )
65 {
66     pthread_t t1,t2;
67 
68     pthread_mutex_init(&mutex, NULL);
69 
70     pthread_cond_init(&cond, NULL);
71 
72     pthread_create(&t1, NULL, thread1, NULL);
73     pthread_create(&t2, NULL, thread2, NULL);
74 
75     //sleep(3);
76 
77     for(size_t i=0; i<1; ++i)
78     {
79         //when send a signal to a cond, if no thread is waiting for this cond, so the signal will lost.
80        
81         pthread_mutex_lock(&mutex);
82         ++g_nums;
83         pthread_cond_signal(&cond);
84         pthread_mutex_unlock(&mutex);
85 
86         //sleep(1);
87     }
88 
89     std::cout<<"Please input the Enter to quit.n";
90     getchar();//sleep(10);
91 
92     return 0;
93 }

运行结果如下:

\"\"

 

这种惊群现象不是必现的,但是有这个风险;所以在编程的时候需要注意这个坑。

造成这种情况的原因:

条件变量在与互斥量配合使用中,wait对互斥进行了如下操作,

1)lock——>2)如果没有可用资源则unlock,同时等待条件唤醒——>3)收到条件通知后——>4)lock——处理任务,dosomething...——>5)unlock

 

从上面的过程可以发现,3)是一个风险点,就像上面的例子一样,thread1和thread2同时收到通知,但thread2处理的快,thread1比较慢,此时thread2处理完任务并unlock,然后thread1才到4)lock,接下来如果thread1继续处理任务就是不对的了,如果是处理一个指针就可能造成系统崩溃;

 

收藏 打印