线程通信(二)—— 条件变量

上篇提到线程针对临界值操作时需要加锁,但是线程访问临界资源只通过锁来控制是不够的。

比如对一个数据进行操作,A线程需要读,B线程进行写。

A线程先访问临界资源,发现没有数据可以读,只能等待B线程先写,此时又占用了互斥锁,导致B线程无法得到锁,进行写操作。

此时就需要用到条件变量了,条件变量的目的就是控制线程的先后执行,保证临界资源的有效性。

下面依然是售票的一个场景,此时一个线程售票,一个线程退票。

  1 #include <pthread.h>
  2 #include <unistd.h>
  3 #include <iostream>
  4
  5 using namespace std;
  6
  7 class ThreadInterface
  8 {
  9 public:
 10     void CreateThread(void* (*func)(void *));
 11     void WaitThread();
 12 private:
 13     pthread_t m_pTread;
 14 };
 15
 16 void ThreadInterface::CreateThread(void* (*func)(void *))
 17 {
 18     pthread_create(&m_pTread, NULL, func, NULL);
 19 }
 20
 21 void ThreadInterface::WaitThread()
 22 {
 23     pthread_join(m_pTread, NULL);
 24 }
 25
 26 class MutexLockInterface
 27 {
 28 public:
 29     void CreateMutexLock();
 30     void GetMutexLock();
 31     void ReleaseMutexLock();
 32     void DestroyMutexLock();
 33     pthread_mutex_t m_MutexLock;
 34 };
 35
 36 void MutexLockInterface::CreateMutexLock()
 37 {
 38     int ret = pthread_mutex_init(&m_MutexLock, NULL);
 39     if (0 != ret)
 40         cout<<"init mutex error!";
 41 }
 42
 43 void MutexLockInterface::GetMutexLock()
 44 {
 45     pthread_mutex_lock(&m_MutexLock);
 46 }
 47
 48 void MutexLockInterface::ReleaseMutexLock()
 49 {
 50     pthread_mutex_unlock(&m_MutexLock);
 51 }
 52
 53 void MutexLockInterface::DestroyMutexLock()
 54 {
 55     pthread_mutex_destroy(&m_MutexLock);
 56 }
 57
 58 class CondInterface
 59 {
 60 public:
 61     void CreateCond();
 62     void WaitCond(pthread_mutex_t *mutex);
 63     void WakeupCond();
 64     void DestroyCond();
 65 private:
 66     pthread_cond_t m_Cond;
 67 };
 68
 69 void CondInterface::CreateCond()
 70 {
 71     int ret = pthread_cond_init(&m_Cond, NULL);
 72     if (0 != ret)
 73         cout<<"init mutex error!";
 74 }
 75 void CondInterface::WaitCond(pthread_mutex_t *mutex)
 76 {
 77     pthread_cond_wait(&m_Cond, mutex);
 78 }
 79 void CondInterface::WakeupCond()
 80 {
 81     pthread_cond_broadcast(&m_Cond);
 82 }
 83 void CondInterface::DestroyCond()
 84 {
 85     pthread_cond_destroy(&m_Cond);
 86 }
 87
 88 class Service
 89 {
 90 public:
 91     static void* run(void *)
 92     {
 93         m_MutexLock.GetMutexLock();
 94         cout<<"we have "<<m_Tickets<<"Tickets"<<endl;
 95         sleep(1);
 96         m_Tickets++;
 97         //Cond.WakeupCond();
 98         m_MutexLock.ReleaseMutexLock();
 99     }
100     int SetData(int data){m_Tickets = data;};
101     int GetData(){return m_Tickets;};
102     static int m_Tickets;
103     static MutexLockInterface m_MutexLock;
104     static CondInterface Cond;
105 };
106 int Service::m_Tickets = 0;
107 MutexLockInterface Service::m_MutexLock;
108 CondInterface Service::Cond;
109
110 int main()
111 {
112     Service Srv;
113     ThreadInterface Thread;
114     Srv.m_MutexLock.CreateMutexLock();
115     Srv.Cond.CreateCond();
116     Thread.CreateThread(&Srv.run);
117
118     Srv.m_MutexLock.GetMutexLock();
119     if (0 == Srv.GetData())
120     {
121         //Srv.Cond.WaitCond(&Srv.m_MutexLock.m_MutexLock);
122         cout<<"wait!"<<endl;
123     }
124
125     cout<<"window1:we have "<<Srv.GetData()<<"Tickets"<<endl;
126     sleep(1);
127     Srv.SetData(Srv.GetData() - 1);
128
129     Srv.m_MutexLock.ReleaseMutexLock();
130     Thread.WaitThread();
131     cout<<Srv.GetData()<<endl;
132     return 0;
133 }

不使用条件变量执行结果如下:

线程1先执行,此时并没有票。此时应该先放弃锁,让线程2先执行,取消注释执行结果如下:

由此可以看出,条件变量让线程1暂时先放弃锁进入阻塞,等线程2执行完毕后,唤醒线程1。再进行正确操作。

时间: 2024-10-15 02:02:31

线程通信(二)—— 条件变量的相关文章

linux线程间通信之条件变量和互斥量

一.条件变量定义 有的时候仅仅依靠锁住共享资源来使用它是不够的.有时候共享资源只有某些状态的时候才能够使用.比方说,某个线程如果要从堆栈中读取数据,那么如果栈中没有数据就必须等待数据被压栈.这种情况下的同步使用互斥锁是不够的.另一种同步的方式--条件变量,就可以使用在这种情况下.条件变量(Condition Variable)是线程间的一种同步机制,提供给两个线程协同完成任务的一种方法,使用条件变量可以以原子方式阻塞线程,直到某个特定条件为真为止.条件变量的测试一般是用互斥量来保护的,用来确保每

Handler与线程通信(二)

1. 准备Looper对象 2. 在WorkerThread当中生成Handler对象 3. 在MainThread当中发送消息 这个过程与上一篇相反 由MainThread里面的Handler发送消息, WorkerThread里面的HandlerMessage来处理 Handler与线程通信(二)

Java基础之线程新特性条件变量

条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了.因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全.条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细 package un

线程&mdash;同步之条件变量

条件变量:允许线程阻塞等待另一个线程发送信号唤醒.条件变量被用来阻塞一个线程,当条件不满足时,线程解开相应的互斥锁并等待条件发生变化.如果其他线程改变了条件变量,并且使用条件变量换型一个或多个正被此条件变量阻塞的线程.这些线程将重新锁定互斥锁并重新测试条件是否满足.条件变量被用来进行线程间的同步. thread 1 con = threading.Condition()    #创建条件变量 while True: do something con.acquire()    #获取锁 con.n

Linux程序设计学习笔记----多线程编程之线程同步之条件变量

转载请注明出处:http://blog.csdn.net/suool/article/details/38582521. 基本概念与原理 互斥锁能够解决资源的互斥访问,但是在某些情况下,互斥并不能解决问题,比如两个线程需 要互斥的处理各自的操作,但是一个线程的操作仅仅存在一种条件成立的情况下执行,一旦错过不可再重现,由于线程间相互争夺cpu资源,因此在条件成立的时候,该线程不一定争夺到cpu而错过,导致永远得不到执行..... 因此需要某个机制来解决此问题,更重要的是,线程仅仅只有一种情况需要执

使用线程间通信之条件变量

最近用C++写安卓下的一个通讯程序,作为jni库给java调用,采用多线程轮询遇到一个问题描述如下: A线程收到数据,放入队列,是生产者. B.C.D若干个线轮询训消息队列,如果队列有数据就取出进行处理,没数据就Sleep(T)休息,问题是这个T值取多大合适?取大了消息处理不及时,取小了手机cpu上升电池很快耗光. 这个问题最佳解法是采用条件变量,可以比较完美解决问题,以下代码使用C++封装,用win32 SDK的条件变量举例,Linux下有完全等价的概念: // 线程消息通知 class Th

四十二、Linux 线程——线程同步之条件变量之线程状态转换

42.1 线程状态转换 42.1.1 状态转换图 42.1.2 一个线程计算,多个线程获取的案例 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pthread.h> 4 #include <unistd.h> 5 6 /** 两个线程定义的共享资源 */ 7 typedef struct { 8 int res; 9 int counter; ///< 用于统计获取结果线程的数量 10 p

线程基础知识系列(四)线程的同步2 线程通信和Condition变量

本文是系列的第四篇. 线程基础知识系列(三)线程的同步  :同步控制,锁及synchronized 线程基础知识系列(二)线程的管理 :线程的状态,控制,休眠,Interrupt,yield等 线程基础知识系列(一)线程的创建和启动  :线程的创建和启动,join(),daemon线程,Callable任务. 第三篇文章,重点阐述了如何使用锁和同步块对线程间共享可变变量保护,保证只有一个线程可以进入临界区.其实,没有过多的涉及另一个重要的同步概念:线程协作.第三篇中涉及的线程间并没有有效的协调.

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

一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保护临界区.条件变量是多线程间可以通过它来告知其他线程某个状态发生了改变,让等待在这个条件变量的线程继续执行.通俗一点来讲:设置一个条件变量让线程1等待在一个临界区的前面,当其他线程给这个变量执行通知操作时,线程1才会被唤醒,继续向下执行. 条件变量总是和互斥量一起使用,互斥量保护着条件变量,防止多个

线程同步之——条件变量

一.生产消费模型:我们可以用条件变量来实现线程之间的同步,利用一个生产消费模型具体的实现同步.生产消费模型可以简单地称为3,2,1模型(即3种关系,2个对象,1个场所),同时还需注意以下3点: 1.生产者和消费者是同步互斥关系: 2.生产者和生产者是互斥关系: 3.消费者和消费者是互斥关系. 二.条件变量的理解:线程A需要等某个条件成才能继续往下执,现在这个条件不成,线程A就阻塞等待,线程B在执过程中使这个条件成了,就唤醒线程A继续执. 在pthread库中通过条件变量(Condition Va