条件变量提供另一种多线程同步的方法。互斥量通过控制对共享数据的访问来同步任务。条件变量可以根据数据的值来同步任务。条件变量是当一个事件发生时发送信号的信号量。一旦事件发生,可能会有多个线程在等待信号,条件变量通常用于对操作的顺序进行同步。使用条件变量对多线程进行同步时,条件变量和互斥量得同时使用。知道这些大概知识,本文将重点探讨怎么使用条件变量进行同步,结构分为三个部分,第一部分给出代码示例,第二部分对代码进行讲解,第三部分给出运行结果。

一、代码示例

#include "StdAfx.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#define NUM_THREADS  3
#define TCOUNT 10
#define COUNT_LIMIT 12

int     count = 0;
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;

void *inc_count(void *t)
{
  int i;
  long my_id = (long)t;

  for (i=0; i < TCOUNT; i++) {
    pthread_mutex_lock(&count_mutex);
    count++;

    /*
    Check the value of count and signal waiting thread when condition is
    reached.  Note that this occurs while mutex is locked.
    */
    if (count == COUNT_LIMIT) {
      printf("inc_count(): thread %ld, count = %d  Threshold reached. ",
             my_id, count);
      pthread_cond_signal(&count_threshold_cv);
      printf("Just sent signal.\n");
      }
    printf("inc_count(): thread %ld, count = %d, unlocking mutex\n",
	   my_id, count);
    pthread_mutex_unlock(&count_mutex);

    /* Do some work so threads can alternate on mutex lock */
    Sleep(10);
    }
  pthread_exit(NULL);
  return(NULL);
}

void *watch_count(void *t)
{
  long my_id = (long)t;

  printf("Starting watch_count(): thread %ld\n", my_id);

  /*
  Lock mutex and wait for signal.  Note that the pthread_cond_wait routine
  will automatically and atomically unlock mutex while it waits.
  Also, note that if COUNT_LIMIT is reached before this routine is run by
  the waiting thread, the loop will be skipped to prevent pthread_cond_wait
  from never returning.
  */
  pthread_mutex_lock(&count_mutex);
  while (count < COUNT_LIMIT) {
    printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id,count);
    pthread_cond_wait(&count_threshold_cv, &count_mutex);
    printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id,count);
    printf("watch_count(): thread %ld Updating the value of count...\n", my_id,count);
    count += 125;
    printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
    }
  printf("watch_count(): thread %ld Unlocking mutex.\n", my_id);
  pthread_mutex_unlock(&count_mutex);
  pthread_exit(NULL);
  return(NULL);
}

int main(int argc, char *argv[])
{
  int i, rc;
  long t1=1, t2=2, t3=3;
  pthread_t threads[3];
  pthread_attr_t attr;

  /* Initialize mutex and condition variable objects */
  pthread_mutex_init(&count_mutex, NULL);
  pthread_cond_init (&count_threshold_cv, NULL);

  /* For portability, explicitly create threads in a joinable state */
  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  pthread_create(&threads[0], &attr, watch_count, (void *)t1);
  pthread_create(&threads[1], &attr, inc_count, (void *)t2);
  pthread_create(&threads[2], &attr, inc_count, (void *)t3);

  /* Wait for all threads to complete */
  for (i = 0; i < NUM_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }
  printf ("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n",
          NUM_THREADS, count);

  /* Clean up and exit */
  pthread_attr_destroy(&attr);
  pthread_mutex_destroy(&count_mutex);
  pthread_cond_destroy(&count_threshold_cv);
  pthread_exit (NULL);

}

二、代码讲解

int     count = 0;
pthread_mutex_t count_mutex;
pthread_cond_t count_threshold_cv;

定义全局变量计数器,互斥量和条件变量

void *inc_count(void *t)
{
  int i;
  long my_id = (long)t;

  for (i=0; i < TCOUNT; i++) {
    pthread_mutex_lock(&count_mutex);
    count++;

    if (count == COUNT_LIMIT) {
      printf("inc_count(): thread %ld, count = %d  Threshold reached. ",
             my_id, count);
      pthread_cond_signal(&count_threshold_cv);
      printf("Just sent signal.\n");
      }
    printf("inc_count(): thread %ld, count = %d, unlocking mutex\n",
	   my_id, count);
    pthread_mutex_unlock(&count_mutex);

    Sleep(10);
    }
  pthread_exit(NULL);
  return(NULL);
}

inc_count()函数是线程2和3执行的任务,每次for循环调用pthread_mutex_lock锁住互斥量,从而对全局变量进行计数,当计数达到一定条件,调用pthread_cond_signal函数发送条件变量,然后对互斥量进行解锁,为了另一个线程有充足时间锁住互斥量,让本线程休眠一段时间,最后退出线程。

void *watch_count(void *t)
{
  long my_id = (long)t;

  printf("Starting watch_count(): thread %ld\n", my_id);

  pthread_mutex_lock(&count_mutex);
  while (count < COUNT_LIMIT) {
    printf("watch_count(): thread %ld Count= %d. Going into wait...\n", my_id,count);
    pthread_cond_wait(&count_threshold_cv, &count_mutex);
    printf("watch_count(): thread %ld Condition signal received. Count= %d\n", my_id,count);
    printf("watch_count(): thread %ld Updating the value of count...\n", my_id,count);
    count += 125;
    printf("watch_count(): thread %ld count now = %d.\n", my_id, count);
    }
  printf("watch_count(): thread %ld Unlocking mutex.\n", my_id);
  pthread_mutex_unlock(&count_mutex);
  pthread_exit(NULL);
  return(NULL);
}

watch_count函数是线程1执行的函数,该线程主要是完成接受发送的条件变量。首先,调用pthread_mutex_lock函数锁住互斥量我;为了使等待时间在有限范围内,使用满足条件的while循环,因为假如count大于条件,那么等待的时间将是无穷无尽的;调用pthread_cond_wait函数接受条件变量,直到接受到条件变量,才执行下一步程序;接受完条件变量后,对互斥量进行解锁,最后退出线程。

 int i, rc;
 long t1=1, t2=2, t3=3;
 pthread_t threads[3];
 pthread_attr_t attr;

 pthread_mutex_init(&count_mutex, NULL);
 pthread_cond_init (&count_threshold_cv, NULL);

定义程序所需变量,pthread_t变量以及属性对象attr;初始化全局互斥量,初始化全局条件变量。

  pthread_attr_init(&attr);
  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  pthread_create(&threads[0], &attr, watch_count, (void *)t1);
  pthread_create(&threads[1], &attr, inc_count, (void *)t2);
  pthread_create(&threads[2], &attr, inc_count, (void *)t3);

  for (i = 0; i < NUM_THREADS; i++) {
    pthread_join(threads[i], NULL);
  }
  printf ("Main(): Waited and joined with %d threads. Final value of count = %d. Done.\n",
          NUM_THREADS, count);

初始化属性对象,并将属性对象设置为可结合的,然后使用该属性对象创建三个线程,分别执行watch_count和inc_count函数,最后结合所有的线程。

  pthread_attr_destroy(&attr);
  pthread_mutex_destroy(&count_mutex);
  pthread_cond_destroy(&count_threshold_cv);
  pthread_exit (NULL);

销毁属性对象、互斥量和条件变量,退出线程。

三、运行结果

学习pthreads,使用条件变量进行多线程之间的同步的更多相关文章

  1. 学习pthreads,创建和终止多线程

    更CPU多线程编程,通过笔者的研究发现,,pthreads使用日趋广泛.它是螺纹POSIX标准,它定义了一组线程的创建和操作API. 配置环境见上博客文章.配置环境后,只需要加入#include &l ...

  2. Linux Qt使用POSIX多线程条件变量、互斥锁(量)

    今天团建,但是文章也要写.酒要喝好,文要写美,方为我辈程序员的全才之路.嘎嘎 之前一直在看POSIX的多线程编程,上个周末结合自己的理解,写了一个基于Qt的用条件变量同步线程的例子.故此来和大家一起分 ...

  3. 条件变量signal与unlock的顺序

    编写同步队列时,有用到条件变量,对操作队列的线程进行同步.当队列为空时,允许get线程挂起,直到add线程向队列添加元素并通过唤醒条件变量,get线程继续向下运行.条件变量在多线程程序中用来实现“等待 ...

  4. linux线程同步(2)-条件变量

    一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...

  5. boost库(条件变量)

    1相关理念 (1)类名 条件变量和互斥变量都是boost库中被封装的类. (2)条件变量 条件变量是thread库提供的一种等待线程同步的机制,可实现线程间的通信,它必须与互斥量配合使用,等待另一个线 ...

  6. posix 条件变量与互斥锁 示例生产者--消费者问题

    一.posix 条件变量 一种线程间同步的情形:线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行. 在pthr ...

  7. linux条件变量

    条件变量用于线程之间的通信,和互斥锁一起使用.条件变量用于及时通知等待的线程条件的变化,使线程不至于错过变化. 考虑下面的情况,有AB两个线程对index这个全局变量进行++,一个线程C用于判断,in ...

  8. c++11中的线程、锁和条件变量

    void func(int i, double d, const string& s) { cout << i << ", " << d ...

  9. [转]一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程

    一个简单的Linux多线程例子 带你洞悉互斥量 信号量 条件变量编程 希望此文能给初学多线程编程的朋友带来帮助,也希望牛人多多指出错误. 另外感谢以下链接的作者给予,给我的学习带来了很大帮助 http ...

随机推荐

  1. 关于java的Synchronized,你可能需要知道这些(下)

    上一篇文章介绍了synchronized的基本使用方法和实现,在实现部分说明了synchronized的底层实现依赖系统互斥锁mutex,但是这个一个重型锁,竞争导致线程阻塞挂起,后续拿到锁后再恢复线 ...

  2. JavaScript 流程语句知识脑图

  3. JavaScript的事件、DOM模型、事件流模型以及内置对象详解(三)

    JS中的事件 JS中的事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresize ...

  4. lglob-lua 静态检查脚本

    ./lglob ~/ngx/lualib/mvc/*.lua 2>&1 | grep ' set '

  5. oh forever love~

    npm install -g forever forever start c9sdk/server.js --listen 0.0.0.0 --port 80 -a aa:111 -w ~ To el ...

  6. React Native(一) FlexBox布局

    欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/53241550 本文出自:[余志强的博客] 在React Native ...

  7. Swift中不用桥接文件和.h头文件直接和C代码交互的方法

    我们知道一般情况下Swit要想调用obj-c,c或c++代码必须通过obj-c以及桥接文件才可以办到,但是对于某些简单的代码,我们可以跳过桥接文件和.h头文件,直接和C代码交互呢! 我们再Projec ...

  8. lucene内存索引库、分词器

    内存索引库 特点 在内存中开辟一块空间,专门为索引库存放.这样有以下几个特征: 1)    因为索引库在内存中,所以访问速度更快. 2)    在程序退出时,索引库中的文件也相应的消失了. 3)    ...

  9. 二维码扫描&集合排序

    一.二维码扫描机制 二维条码/二维码(2-dimensional bar code)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的:在代码编制上巧妙地利用构 ...

  10. ROS讲座 关于ROS2和Gazebo C++ in Open Source Robotics

    分享一个不错的介绍ROS2和Gazebo的视频讲座. Gazebo中的云彩飘动起来了!!!! 超清视频分享网址:    http://v.youku.com/v_show/id_XMTcyMzY0Nz ...