zoukankan      html  css  js  c++  java
  • 学习apue的pthread synchronize之condition variables

    学习apue11.6.6 condition variables实践:

    使用书上的condition variables和wait函数

     1 #include<pthread.h>
     2 #include<stdio.h>
     3 #include<iostream>
     4 
     5 using namespace std;
     6 
     7 bool flag = false;
     8 pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
     9 pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;
    10 void * printid(void *i)
    11 {
    12     pthread_mutex_lock(&qlock);
    13     while(!flag)
    14         pthread_cond_wait(&qready,&qlock);
    15     printf("thread id is : %lu
    ",(unsigned long)pthread_self());
    16     //return ((void *)0);
    17     pthread_mutex_unlock(&qlock);
    18     pthread_exit((void *)1);
    19 }
    20 void go()
    21 {
    22     pthread_mutex_lock(&qlock);
    23     flag = true;
    24     pthread_mutex_unlock(&qlock);
    25     pthread_cond_signal(&qready); // 第一种结果
        //pthread_cond_broadcast(&qready); //第二种结果
    26 } 27 pthread_t ths[10]; 28 int main() 29 { 30 31 for(int i = 0;i<10;++i){ 32 pthread_create(&ths[i],NULL,printid,NULL); 33 } 34 go(); 35 for(int i=0;i<10;++i){ 36 pthread_join(ths[i],NULL); 37 } 38 exit(0); 39 }

    参考c++11 的condition variables:http://blog.csdn.net/hujingshuang/article/details/70596630

     1     #include <iostream>                 // std::cout  
     2     #include <thread>                   // std::thread  
     3     #include <mutex>                    // std::mutex, std::unique_lock  
     4     #include <condition_variable>       // std::condition_variable  
     5       
     6     using namespace std;  
     7       
     8     mutex mtx;                          // 互斥量  
     9     condition_variable cv;              // 条件变量  
    10     bool ready = false;                 // 标志量  
    11       
    12     void print_id(int id) {  
    13         unique_lock<mutex> lck(mtx);    // 上锁  
    14         while (!ready) {  
    15             cv.wait(lck);               // 线程等待直到被唤醒(释放锁 + 等待,唤醒,在函数返回之前重新上锁)  
    16         }  
    17         cout << "thread " << id << '
    ';  
    18     }  
    19       
    20     void go() {  
    21         unique_lock<mutex> lck(mtx);    // 上锁  
    22         ready = true;  
    23         cv.notify_all();                // 唤醒所有正在等待(挂起)的线程(在这里面要释放锁,为了在wait函数返回之前能成功的重新上锁)  
    24     }  
    25       
    26     int main() {  
    27         thread threads[10];  
    28         for (int i = 0; i<10; ++i) {  
    29             threads[i] = thread(print_id, i);  
    30         }  
    31       
    32         cout << "10 threads ready to race...
    ";  
    33         go();  
    34       
    35         for (auto& th : threads) {  
    36             th.join();  
    37         }  
    38       
    39         return 0;  
    40     }  

       首先,定义了几个全局变量:互斥量(mtx)、条件变量(cv)、标志量(ready)。整个代码的作用就是,当10个线程都准备好了之后,再并发执行(就好像赛马,把马牵出来,当所有马匹在赛道上就绪之后,再开始跑),也就是使用条件变量起到同步的作用。

            在代码中结合使用了mutex与condition_variable,请大家仔细阅读一下代码,然后再仔细阅读下面的解析:

                    1、在print_id中,线程先将互斥量上锁(使用的unique_lock<mutex>),再判断ready,若ready为false,说明条件不满足,那么调用条件变量的wait()方法将线程挂起;

                    2、当所有的线程都在等待状态时,说明所有线程已就绪,此时在主线程中将ready设为true,并调用notify_all()将所有挂起线程唤醒;

                    3、所有线程被唤醒之后,并发执行打印自己的id;

                    4、使用thread::join()方法,等所有线程都执行完毕,主线程才接着执行,直到出现结束。

            我们举例代码的运行过程就是这样,但是我们仔细想一想第1个过程:当有一个线程一来,就将互斥量先上了锁,然后发现条件不满足,就进入了挂起状态,此时代码中并没有解锁操作,那么该线程就一直持有锁(锁被独占了),这样的话其他线程根本就没有机会获取锁,那还谈什么后面的全部线程挂起、并发执行呢?

            实际上,上述分析并没有错,确实是这样的道理。但是这种问题是怎么解决的呢,其实这就是条件变量对象中wait()、notify()方法要处理的了,过程如下:

                    1、线程A一来,就将互斥量上锁(持有了锁),ready为false,那么线程A将调用条件变量的wait()方法;

                    2、在wait()方法中,做的第一件事就是将互斥量解锁(释放持有权),并进入等待状态(在wait()中阻塞,线程A挂起);

                    3、现在线程B来了,互斥量是没有上锁的,所以线程B能持有锁,同理,接下来线程B也会挂起;

                    4、当所有线程都挂起了(就绪),此时互斥量也没有被上锁,在主线程中将ready置为true,并调用notify_all()将所有挂起的线程都唤醒;

                    5、此时所有线程将从wait()方法中返回,比如线程C先返回,在return之前,wait()方法做的最后一件事就是自动将互斥量上锁(线程C重新持有锁,以配合unique_lock的析构函数);

                   6、由于while循环,此时再判断到ready为true,那么线程C将执行打印id的语句,由于此时只有线程C持有锁,不存在线程竞争问题,执行完打印之后,线程C就结束了,此时由unique_lock的析构函数解锁,释放所有权。

                    7、由于在wait()方法return之前,会自动重新去持有锁,若此时锁由线程C持有,则其他线程将继续阻塞,直到线程C释放锁;若线程C执行完毕后释放了锁,那么其他线程将会争取锁的持有权,争取到锁的就会像之前的线程C一样;没有争取到的就继续阻塞;

                    8、以此类推,由于每个线程都join,那么当所有线程执行完毕后,主线程才会继续执行;

  • 相关阅读:
    程序员常用英语词汇
    声明式编程与命令式编程
    vue 常用ui组件库
    Vue 组件之间传值
    vscode插件之背景插件(background)
    iconfont的使用
    CSS3 @font-face 规则
    CSS抗锯齿 font-smoothing 属性介绍
    new Image 读取宽高为0——onload
    js的for循环中出现异步函数,回调引用的循环值始终是最后的值
  • 原文地址:https://www.cnblogs.com/CreatorKou/p/8562141.html
Copyright © 2011-2022 走看看