>

有了互斥量,linux下规范变量使用笔记

- 编辑:正版管家婆马报彩图 -

有了互斥量,linux下规范变量使用笔记

此次笔记记录三个难点:

 

1,条件变量在选取时会有功率信号错失现象;(使用g_nums记录数字信号,幸免时限信号遗失)

一、互斥量和原则变量简单介绍

  互斥量(mutex)从本质上说是一把锁,在访谈分享财富前对互斥量举行加锁,在访谈成功后获释互斥量上的锁。在互斥量进行加锁未来,任何别的试图再一次对互斥量加锁的线程将会阻塞直到当前线程释放该互斥锁。要是释放互斥锁时有多个线程阻塞,全体在该互斥锁上的不通线程都会化为可运转状态,第多少个形成可运市场价格况的线程能够对互斥锁加锁,另外线程将会看出互斥锁依然被锁住,只可以回去重新等待它再也产生可用。

  条件变量(cond)是在十二线程程序中用来落到实处“等待--》唤醒”逻辑的常用的方式。条件变量是利用线程间分享的全局变量进行共同的一种机制,首要包罗多个动作:贰个线程等待“条件变量的条件建设构造”而挂起;另一个线程使“条件建构”。条件变量的施用总是和三个排斥锁结合在一块儿。线程在改造法则状态前必得首先锁住互斥量,函数pthread_cond_wait把温馨置于等待条件的线程列表上,然后对互斥锁解锁,那四个操作是原子操作(所谓原子操作是指不会被线程调节机制打断的操作;这种操作一旦伊始,就直接运营到甘休,中间不会有别的context switch(切换来另贰个线程))。在函数再次来到时,互斥量再次被锁住。

2,条件变量的wait内部锁操作会在惊群现象的时候访问不可用能源,存在潜在的高风险;(wait后再一次对可用能源进行决断,制止操作不可用能源景况的产生)

二、为何存在条件变量

  首先,例如:在应用程序中有4个经过thread1,thread2,thread3和thread4,有三个int类型的全局变量iCount。iCount早先化为0,thread1和thread2的意义是对iCount的加1,thread3的意义是对iCount的值减1,而thread4的法力是当iCount的值大于等于100时,打字与印刷提示音信相提并论置iCount=0。

  假诺采纳互斥量,线程代码大约应是上面的规范:

thread1/2:
       while (1)
       {
             pthread_mutex_lock(&mutex);
             iCount++;
             pthread_mutex_unlock(&mutex);
       }
       thread4:
       while(1)
       {
             pthead_mutex_lock(&mutex);
             if (100 <= iCount)
             {
                   printf("iCount >= 100rn");
                   iCount = 0;
                   pthread_mutex_unlock(&mutex);
             }
             else
             {
                   pthread_mutex_unlock(&mutex);
             }
       }

  在地方代码中出于thread4并不知道曾几何时iCount会大于等于100,所以就能直接在循环判别,不过每一遍判定都要加锁、解锁(纵然此次并从未更动iCount)。那就带来了难点一:CPU浪费严重。所以在代码中增添了sleep(),那样让每一回决断都休眠一定时间。但这又带来的第三个难点:借使sleep()的日子相比较长,导致thread4处理相当不足及时,等iCount到了非常的大的值时才重新初始化。对于地方的三个难题,能够行使条件变量来解决。

  首先看一下利用标准变量后,线程代码差不离的标准:

thread1/2:
       while(1)
       {
               pthread_mutex_lock(&mutex);
               iCount++;
               pthread_mutex_unlock(&mutex);
               if (iCount >= 100)
               {
                      pthread_cond_signal(&cond);
               }
       }         
       thread4:
       while (1)
       {
              pthread_mutex_lock(&mutex);
              while(iCount < 100)
              {
                     pthread_cond_wait(&cond, &mutex);
              }
              printf("iCount >= 100rn");
              iCount = 0;
              pthread_mutex_unlock(&mutex);
       }       

  从上边的代码能够见到thread4中,当iCount < 100时,会调用pthread_cond_wait。而pthread_cond_wait在上头应经讲到它会放出mutex,然后等待条件成为真回来。当再次来到时会再一次锁住mutex。因为pthread_cond_wait会等待,进而不用直接的轮询,收缩CPU的浪费。在thread1和thread第22中学的函数pthread_cond_signal会唤醒等待cond的线程(即thread4),那样当iCount一到过量等于100就能去唤醒thread4。进而不致出现iCount相当的大了,thread4才去管理。

  须求小心的一些是在thread4中选拔的while (iCount < 100),而不是if (iCount < 100)。那是因为在pthread_cond_singal()和pthread_cond_wait()重回之间不经常光差,假若在时刻差内,thread3又将iCount减到了100以下了,那么thread4在pthread_cond_wait()返回之后,显明应该再自己商议三遍iCount的大大小小,那就是while的意向,要是是if,则会直接往下实行,不会另行决断。

  以为可以计算为:条件变量用于有些线程须要在某种条件建马上才去敬服它将在操作的临界区,这种景况于是制止了线程不断轮询检查该原则是或不是构建而裁减成效的动静,那是完毕了功效进步。在尺度满足时,自动退出阻塞,再加锁进行操作。

  IBM上有个关于标准变量的稿子: ,也得以看看。

 

2017-10-09 15:23:43补充:

1、

问:条件变量为啥要与pthread_mutex一齐行使啊?

答:那是为了回应线程1在调用pthread_cond_wait()但线程1还尚未进去wait cond的意况的时候,此时线程2调用了 cond_singal 的情事。 假若不用mutex锁的话,那些cond_singal就不见了。加了锁的意况是,线程2必得等到 mutex 被放走(也正是 pthread_cod_wait() 释放锁并跻身wait_cond状态 ,此时线程2上锁) 的时候技能调用cond_singal

2、

调用pthread_cond_signal后要及时释放互斥锁(也能够将pthread_cond_signal放在pthread_mutex_lock和pthread_mutex_unlock之后),因为pthread_cond_wait的末段一步是要将钦赐的互斥量重新锁住,尽管pthread_cond_signal之后未有自由互斥锁,pthread_cond_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 10 void* thread1( void* arg)11 {12     while(1)13     {14 15         pthread_mutex_lock(&mutex);16 17         pthread_cond_wait(&cond, &mutex);18 19         std::cout<<"the thread1 info: "<<std::endl;20     21         pthread_mutex_unlock(&mutex);    22         sleep(1);23     }24 25     return NULL;26 }27 28 void* thread2(void* arg)29 {30 31     while(true){32         pthread_mutex_lock(&mutex);33        34         pthread_cond_wait(&cond, &mutex);35 36         std::cout<<"the thread2 info: "<<std::endl;37 38         pthread_mutex_unlock(&mutex);39 40         sleep(1);41     }42 43     return NULL;44 }45 46 47 int main( int argc, char*argv[] )48 {49     pthread_t t1,t2;50 51     pthread_mutex_init(&mutex, NULL);52 53     pthread_cond_init(&cond, NULL);54 55     pthread_create(&t1, NULL, thread1, NULL);56     pthread_create(&t2, NULL, thread2, NULL);57 58     //sleep;59 60     for(size_t i=0; i<10; ++i)61     {62         //when send a signal to a cond, if no thread is waiting for this cond, so the signal will lost.63        64         pthread_mutex_lock(&mutex);65         pthread_cond_signal(&cond);66         pthread_mutex_unlock(&mutex);67 68         //sleep;69     }70 71     std::cout<<"Please input the Enter to quit.n";72     getchar();//sleep;73 74     return 0;75 }

运转结果:

图片 1

可知,发送了拾肆遍时域信号,条件变量却只接触了二遍。该难题的技术方案会在末端给出的代码中写出,即便用g_nums来记录条件复信号的个数。

上面来看看该笔记中的2)这种景象,惊群现象。。。

 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;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;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;87     }88 89     std::cout<<"Please input the Enter to quit.n";90     getchar();//sleep;91 92     return 0;93 }

运作结果如下:

图片 2

这种惊群现象不是必现的,可是有其一危机;所以在编制程序的时候须求小心这些坑。

导致这种景况的来头:

标准变量在与互斥量合营使用中,wait对互斥举行了如下操作,

1)lock——>2)若无可用能源则unlock,同一时候等待条件唤醒——>3)收到条件通告后——>4)lock——管理职务,dosomething...——>5)unlock

从上面包车型客车进度能够窥见,3)是贰个危机点,就疑似上面的事例同样,thread1和thread2同期抽出文告,但thread2管理的快,thread1异常慢,此时thread2管理完职务并unlock,然后thread1才到4)lock,接下去假设thread1继续管理任务正是颠三倒四的了,尽管是拍卖一个指针就恐怕形成系统崩溃;

正文为原创小说,假设转发请写明出处

本文由编程应用发布,转载请注明来源:有了互斥量,linux下规范变量使用笔记