详细见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*函数中的线程就会被唤醒。

先来看一段代码:

  1. // 条件变量.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <windows.h>
  5. #include <iostream>
  6. #include <vector>
  7. #include <process.h>
  8. using namespace std;
  9. DWORD WINAPI ThreadProduce(PVOID pvParam);
  10. DWORD WINAPI ThreadUser1(PVOID pvParam);
  11. DWORD WINAPI ThreadUser2(PVOID pvParam);
  12. vector<int> ivec;
  13. SRWLOCK g_lock;
  14. SRWLOCK g_lock2;
  15. CONDITION_VARIABLE g_ConditionVar;
  16. int _tmain(int argc, _TCHAR* argv[])
  17. {
  18. InitializeSRWLock(&g_lock);//初始化锁
  19. //创建生产者
  20. HANDLE hThread1 = (HANDLE)_beginthreadex(NULL,0,(unsigned int(_stdcall *)(void*))ThreadProduce,NULL,0,0);
  21. //创建读取者线程
  22. HANDLE hThread2 = (HANDLE)_beginthreadex(NULL,0,(unsigned int(_stdcall *)(void*))ThreadUser,(PVOID)1,0,0);
  23. HANDLE hThread3 = (HANDLE)_beginthreadex(NULL,0,(unsigned int(_stdcall *)(void*))ThreadUser,(PVOID)2,0,0);
  24. WaitForSingleObject(hThread1,INFINITE);
        WaitForSingleObject(hThread2,INFINITE);
        WaitForSingleObject(hThread3,INFINITE);
  25. CloseHandle(hThread1);
  26. CloseHandle(hThread2);
  27. CloseHandle(hThread3);
  28. system("pause");
  29. return 0;
  30. }
  31. DWORD WINAPI ThreadProduce(PVOID pvParam)
  32. {
  33. for(int i=0; i<10000; ++i)
  34. {
  35. AcquireSRWLockExclusive(&g_lock);  //获得SRW锁
  36. ivec.push_back(i);
  37. ReleaseSRWLockExclusive(&g_lock);  //释放SRW锁
  38. WakeConditionVariable(&g_ConditionVar);  //因为,每次执行push_back 后,容器里就会必定至少有一个元素(生产者
  39. //生产出东西了)这时候阻塞在Sleep*里的线程被唤醒 (读取者sleep的线程)。
  40. // Sleep(1000);//停一下,让读取者先读
  41. }
  42. return 0;
  43. }
  44. DWORD WINAPI ThreadUser(PVOID p)
  45. {
  46.   ULONG UserId = (ULONG)(ULONG_PTR)p;
  47. while(1)
  48. {
  49. AcquireSRWLockExclusive(&g_lock);
  50. while(ivec.empty())
  51. {
  52. cout<<"等待写入"<<endl;
  53. //如果容器是空的,也就是没有内容可以读,那么让线程进入睡眠状态,一直到调用WakeConditionAllVariable(&g_ConditionVar);
  54. SleepConditionVariableSRW(&g_ConditionVar,&g_lock,INFINITE,NULL);  //如果为CONDITION_VARIABLE_LOCKMODE_SHARED,会出错
  55. }
  56. cout<<"线程"<<UserId<<":"<<ivec.back()<<endl;
  57. ivec.pop_back();
  58. ReleaseSRWLockExclusive(&g_lock);
  59. }
  60. return 0;
  61. }

分析一下这段代码,其实很简单,具体可以从代码注释中看。之前,写这段代码的时候犯过几个错误:

(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条件变量的更多相关文章

  1. Windows:C++11并发编程-条件变量(condition_variable)详解

    <condition_variable >头文件主要包含了与条件变量相关的类和函数.相关的类包括 std::condition_variable和 std::condition_varia ...

  2. Linux线程同步:条件变量

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

  3. 第8章 用户模式下的线程同步(4)_条件变量(Condition Variable)

    8.6 条件变量(Condition Variables)——可利用临界区或SRWLock锁来实现 8.6.1 条件变量的使用 (1)条件变量机制就是为了简化 “生产者-消费者”问题而设计的一种线程同 ...

  4. C++11并行编程-条件变量(condition_variable)详细说明

    <condition_variable >头文件主要包含有类和函数相关的条件变量. 包括相关类 std::condition_variable和 std::condition_variab ...

  5. 学习pthreads,使用条件变量进行多线程之间的同步

    条件变量提供另一种多线程同步的方法.互斥量通过控制对共享数据的访问来同步任务.条件变量可以根据数据的值来同步任务.条件变量是当一个事件发生时发送信号的信号量.一旦事件发生,可能会有多个线程在等待信号, ...

  6. pThreads线程(三) 线程同步--条件变量

    条件变量(Condition Variables) 参考资料:http://game-lab.org/posts/posix-thread-cn/#5.1 条件变量是什么? 条件变量为我们提供了另一种 ...

  7. 多线程编程中条件变量和的spurious wakeup 虚假唤醒

    1. 概述 条件变量(condition variable)是利用共享的变量进行线程之间同步的一种机制.典型的场景包括生产者-消费者模型,线程池实现等. 对条件变量的使用包括两个动作: 1) 线程等待 ...

  8. Linux多线程编程的条件变量

    在stackoverflow上看到一关于多线程条件变量的问题,题主问道:什么时候会用到条件变量,mutex还不够吗?有个叫slowjelj的人做了很好的回答,我再看这个哥们其他话题的一些回答,感觉水平 ...

  9. POSIX多线程编程-条件变量pthread_cond_t

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

随机推荐

  1. 分布式技术 webservice

    web service 是一个平台独立的.低耦合的.自包含的.基于编程的web的应用程序,可使用开发的XML(标准通用标记语言下的一个字表)标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布 ...

  2. 让外界可以访问电脑上的网站的几种方式——花生壳,域名,IIS(待)

    前话: 每次“养大“一个网站,都有种骄傲地想秀给朋友们看的冲动. 之前可能是困于电脑,实在不方便. 现在,不用克制了! 该秀就秀,能装逼就装逼. 养大孩子就该拉出来秀秀,见见世面. 正题:这次实习,我 ...

  3. HRBUST 2072 树上求最大异或路径值

    一个很经典的套路 思想是 F [u,v] = F[1,u] ^ F[1,v] 这样就转化成了n个数两两异或 求最大值 可以用字典树来做 每次用当前数去树中寻求最大xor值 然后把这个数字插进去 就相当 ...

  4. 使用标签代替goto关键字

    众所周知,java中没有goto语句,但是保留了goto这个关键字.由于goto是在源码级上的跳转,多次使用goto会引起代码混乱容易出错,这也是java取消goto语句的目的所在,但是goto语句也 ...

  5. JMeter报错 ERROR o.a.j.t.JMeterThread: Test failed!

    第一次用JMeter,然后跟着教程走,发现进行测试的时候直接报错 显示如下 反复测试依然报错,网上搜索也没什么结果,自己测试了一下才发现问题. 左边创建了CSV DATA 但是并没有进行设置  导致报 ...

  6. 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 9851  Solved: 4318[Submi ...

  7. linux(ubuntu16.04)下安装和破解pycharm专业版

    我用的linux 版本是ubuntu,查看版本命令是: lsb_release -a 因为学习Python爬虫,pycharm是Python很好用的IDE,但是专业版需要付费,所以开始安装: 首先在官 ...

  8. Python内置函数-enumerate

    enumerate 函数用于遍历序列中的元素以及它们的下标:(返回index,value) >>> for i,j in enumerate(('a','b','c')): prin ...

  9. Python安装升级步骤

    1)安装Pyhton2.7wget http://www.python.org/ftp/python/2.7.5/Python-2.7.5.tar.bz2tar xjvf Python-2.7.5.t ...

  10. kvm-控制台登陆配置

    vm虚拟机能否像xen虚拟机一样通过virsh console 一样采用字符界面进行linux虚拟机控制台呢,答案是肯定的,默认情况下该命令是不起作用的,需要修改相关文件才能实现. 1. 配置方法如下 ...