Windows条件变量
详细见MSDN:http://msdn.microsoft.com/en-us/library/windows/desktop/ms686903%28v=vs.85%29.aspx
我们已经看到,当想让写入者线程和读取者线程以独占的方式或共享的方式访问一个资源的时候,可以使用SRWLock。在这些情况下,如果读取者线程 没有数据可以读取,那么它应该将锁释放并等待,直到写入者线程产生了新的数据为止。如果用来接收写入者线程产生的数据结构已满,那么写入者同样应该释放 SRWLock并进入睡眠状态,直到读取这线程把数据结构清空为止。
我们希望线程以原子的方式把锁释放并将自己阻塞,直到某一个条件成立为止。要实现这样的线程同步是比较复杂的。Windows通过 SleepConditionVariableCS(critical section) 或者SleepConditionVariableSRW 函数,提供了一种 条件变量 帮助我们完成这项工作。
当线程检测到相应的条件满足的时候(比如,有数据供读取者使用),它会调用 WakeConditionVariable 或 WakeAllConditionVariable,这样阻塞在Sleep*函数中的线程就会被唤醒。
先来看一段代码:
- // 条件变量.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include <windows.h>
- #include <iostream>
- #include <vector>
- #include <process.h>
- using namespace std;
- DWORD WINAPI ThreadProduce(PVOID pvParam);
- DWORD WINAPI ThreadUser1(PVOID pvParam);
- DWORD WINAPI ThreadUser2(PVOID pvParam);
- vector<int> ivec;
- SRWLOCK g_lock;
- SRWLOCK g_lock2;
- CONDITION_VARIABLE g_ConditionVar;
- int _tmain(int argc, _TCHAR* argv[])
- {
- InitializeSRWLock(&g_lock);//初始化锁
- //创建生产者
- HANDLE hThread1 = (HANDLE)_beginthreadex(NULL,0,(unsigned int(_stdcall *)(void*))ThreadProduce,NULL,0,0);
- //创建读取者线程
- HANDLE hThread2 = (HANDLE)_beginthreadex(NULL,0,(unsigned int(_stdcall *)(void*))ThreadUser,(PVOID)1,0,0);
- HANDLE hThread3 = (HANDLE)_beginthreadex(NULL,0,(unsigned int(_stdcall *)(void*))ThreadUser,(PVOID)2,0,0);
- WaitForSingleObject(hThread1,INFINITE);
WaitForSingleObject(hThread2,INFINITE);
WaitForSingleObject(hThread3,INFINITE); - CloseHandle(hThread1);
- CloseHandle(hThread2);
- CloseHandle(hThread3);
- system("pause");
- return 0;
- }
- DWORD WINAPI ThreadProduce(PVOID pvParam)
- {
- for(int i=0; i<10000; ++i)
- {
- AcquireSRWLockExclusive(&g_lock); //获得SRW锁
- ivec.push_back(i);
- ReleaseSRWLockExclusive(&g_lock); //释放SRW锁
- WakeConditionVariable(&g_ConditionVar); //因为,每次执行push_back 后,容器里就会必定至少有一个元素(生产者
- //生产出东西了)这时候阻塞在Sleep*里的线程被唤醒 (读取者sleep的线程)。
- // Sleep(1000);//停一下,让读取者先读
- }
- return 0;
- }
- DWORD WINAPI ThreadUser(PVOID p)
- {
- ULONG UserId = (ULONG)(ULONG_PTR)p;
- while(1)
- {
- AcquireSRWLockExclusive(&g_lock);
- while(ivec.empty())
- {
- cout<<"等待写入"<<endl;
- //如果容器是空的,也就是没有内容可以读,那么让线程进入睡眠状态,一直到调用WakeConditionAllVariable(&g_ConditionVar);
- SleepConditionVariableSRW(&g_ConditionVar,&g_lock,INFINITE,NULL); //如果为CONDITION_VARIABLE_LOCKMODE_SHARED,会出错
- }
- cout<<"线程"<<UserId<<":"<<ivec.back()<<endl;
- ivec.pop_back();
- ReleaseSRWLockExclusive(&g_lock);
- }
- return 0;
- }
分析一下这段代码,其实很简单,具体可以从代码注释中看。之前,写这段代码的时候犯过几个错误:
(1)AcquireSRWLockExclusive() ReleaseSRWLockExclusive() 和 AccquireSRWLockShare() ReleaseSRWLockShare() 两对函数之间的区别
前者获得的对保护资源的 独占 访问权 而后者获得是 保护资源的 共享访问权,因为虽然 代码里的读线程,在读取数据的同时,他也pop_back()了容器里的内容,也就是可以看作是“写”,因为,我们必须获得的是 独占 访问权。
(2)WakeConditionVariabel() 和 WakeAllconditionVariable() 的区别:
当调用 前者的时候,会使一个在 SleepConditionVariable*函数中等待同一个条件变量被触发的线程得到锁并返回。当这个线程释放同一个锁的时候,不会唤醒其他正在等待同一个条件变量的线程
当调用后者的时候,会使一个或几个在SleepConditionVariable*函数中等待这个条件变量触发的线程达到对资源的访问权并返回。
(3)
BOOL WINAPI SleepConditionVariableSRW(
__in_out PCONDITION_VARIABLE ConditionVariable, //线程休眠相关的条件变量
__in_out PSRWLOCK SRWLock, //指向一个SRWLock的指针
__in DWORD dwMilliseconds, //希望等待的时间,可以为INFINITE
__in ULONG Flags
);
该函数一原子操作的方式执行了两个操作:
1.释放SRWLock指向的锁;
2.把线程休眠。
如果参数Flags是 CONDITION_VARIABLE_LOCKMODE_SHARED,那么在同一时刻可以允许多个读取者线程得到锁,如果线程修改数据,这可能导致数据冲突。
Windows条件变量的更多相关文章
- Windows:C++11并发编程-条件变量(condition_variable)详解
<condition_variable >头文件主要包含了与条件变量相关的类和函数.相关的类包括 std::condition_variable和 std::condition_varia ...
- Linux线程同步:条件变量
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
- 第8章 用户模式下的线程同步(4)_条件变量(Condition Variable)
8.6 条件变量(Condition Variables)——可利用临界区或SRWLock锁来实现 8.6.1 条件变量的使用 (1)条件变量机制就是为了简化 “生产者-消费者”问题而设计的一种线程同 ...
- C++11并行编程-条件变量(condition_variable)详细说明
<condition_variable >头文件主要包含有类和函数相关的条件变量. 包括相关类 std::condition_variable和 std::condition_variab ...
- 学习pthreads,使用条件变量进行多线程之间的同步
条件变量提供另一种多线程同步的方法.互斥量通过控制对共享数据的访问来同步任务.条件变量可以根据数据的值来同步任务.条件变量是当一个事件发生时发送信号的信号量.一旦事件发生,可能会有多个线程在等待信号, ...
- pThreads线程(三) 线程同步--条件变量
条件变量(Condition Variables) 参考资料:http://game-lab.org/posts/posix-thread-cn/#5.1 条件变量是什么? 条件变量为我们提供了另一种 ...
- 多线程编程中条件变量和的spurious wakeup 虚假唤醒
1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...
- Linux多线程编程的条件变量
在stackoverflow上看到一关于多线程条件变量的问题,题主问道:什么时候会用到条件变量,mutex还不够吗?有个叫slowjelj的人做了很好的回答,我再看这个哥们其他话题的一些回答,感觉水平 ...
- POSIX多线程编程-条件变量pthread_cond_t
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
随机推荐
- Codeforces Round #370 (Div. 2) A , B , C 水,水,贪心
A. Memory and Crow time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- git 里面遇到的问题
第一步:建立git仓库(本地) cd到你的本地项目根目录下,执行git命令 git init 第二步:将项目的所有文件添加到仓库中 git add . 如果想添加某个特定的文件,只需把.换成特定的文件 ...
- phpPgAdmin (win)配置安装及远程访问
phpPgAdmin (win)配置安装 [1] 通过PostgreSQL的Application Stack Builder配置安装phpPgAdmin 1.确保PostgreSQL安装并正 ...
- JProgressBar与Timer的配套使用
JProgressBar 的关键在于 setMaxium(int maxValue) 和 setValue(int progressValue); 当ProgressBar的当前值需要Control ...
- Secret Code
Secret Code 一.题目 [NOIP模拟赛A10]Secret Code 时间限制: 1 Sec 内存限制: 128 MB 提交: 10 解决: 6 [提交][状态][讨论版] 题目描述 ...
- 维度属性的KeyColumns,NameColumn和ValueColumn
维度的每一个属性都有KeyColumns,NameColumn和ValueColumn 1,如何理解KeyColumns,NameColumn和ValueColumn?对一行记录有不同的标识列,但 ...
- PHP版微信第三方实现一键登录及获取用户信息的方法
本文实例讲述了PHP版微信第三方实现一键登录及获取用户信息的方法.分享给大家供大家参考,具体如下: 注意,要使用微信在第三方网页登录是需要“服务号”才可以哦,所以必须到官方申请. 一开始你需要进入微信 ...
- Eclipse中Maven的本地仓库引导配置
简单整理一下,方便理解操作. 1.本地拷贝maven文件后,打开maven中的.setting 文件: 2.配置文件: <?xml version="1.0" encodin ...
- 使用BackgroundWorker组件
BackgroundWorker 组件用来执行诸如数据库事务.文件下载等耗时的异步操作. 开始 在应用程序中添加一个BackgroundWorker实例,如果用的是VS,可以从工具上直接拖到应用程序: ...
- 常用stl(c++)
众所周知,c++的模板库是相当强大的. 下面我来列举一些常用的,(神奇的) //部分材料选自<算法竞赛入门经典(第2版)>(刘汝佳) 一,algorithm (算法) min(a,b)-- ...