1.  互斥量,Mutex

  1. #include <Windows.h>
  2. #include <iostream>
  3. using namespace std;
  4. DWORD WINAPI Thread1(LPVOID lpParmeter);
  5. DWORD WINAPI Thread2(LPVOID lpParmeter);
  6. static HANDLE g_hMutex = INVALID_HANDLE_VALUE;
  7. static int g_iCnt = 100;
  8. int main()
  9. {
  10. HANDLE hThread1 = INVALID_HANDLE_VALUE;
  11. HANDLE hThread2 = INVALID_HANDLE_VALUE;
  12. g_hMutex = CreateMutex(NULL, FALSE, "Mutex");
  13. // 第二个参数:创建者是否拥有所有权,FALSE为没有所有权,
  14. // 遇到第一个WaitForSingleObject的时候就把所有权给它,
  15. // 所以Thread1里面的WaitForSingleObject(g_hMutex, INFINITE)能够继续执行
  16. if (!g_hMutex)
  17. {
  18. cout << "Failed to CreateMutex !" << endl;
  19. return 0;
  20. }
  21. hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
  22. hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
  23. Sleep(4000);        // 让2个线程有足够的时间执行完操作。
  24. CloseHandle(hThread1);
  25. CloseHandle(hThread2);
  26. system("PAUSE");
  27. return 0;
  28. }
  29. DWORD WINAPI Thread1(LPVOID lpParmeter)
  30. {
  31. while (true)
  32. {
  33. // 请求事件对象
  34. WaitForSingleObject(g_hMutex, INFINITE);    // INFINITE: 长时间等待,差不多50天左右吧!
  35. if (g_iCnt > 0)
  36. {
  37. Sleep(20);
  38. cout << "Thread1:" << g_iCnt-- << endl;
  39. ReleaseMutex(g_hMutex);                 // 释放资源
  40. }
  41. else
  42. {
  43. ReleaseMutex(g_hMutex);
  44. break;
  45. }
  46. }
  47. return 0;
  48. }
  49. DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
  50. {
  51. while (true)
  52. {
  53. // 请求事件对象
  54. WaitForSingleObject(g_hMutex,INFINITE);
  55. if (g_iCnt > 0)
  56. {
  57. Sleep(20);
  58. cout << "thread2:" << g_iCnt-- << endl;
  59. ReleaseMutex(g_hMutex);
  60. }
  61. else
  62. {
  63. ReleaseMutex(g_hMutex);
  64. break;
  65. }
  66. }
  67. return 0;
  68. }

几个注意的地方:

(1)互斥量为内核对象,能够与其他线程或特殊事件取得同步;

(2)速度比临界区要慢;

(3)互斥量对象与所有其它内核对象的不同之处在于它是被线程所拥有的,互斥量对象除了记录当前信号状态外,还要记住此时那个线程拥有它。

(4)这个常来被运用于限制程序启动次数!

2.事件 Event

  1. #include <Windows.h>
  2. #include <iostream>
  3. using namespace std;
  4. DWORD WINAPI Thread1(LPVOID lpParmeter);
  5. DWORD WINAPI Thread2(LPVOID lpParmeter);
  6. static HANDLE g_hEvent = INVALID_HANDLE_VALUE;
  7. static int g_iCnt = 100;
  8. int main()
  9. {
  10. HANDLE hThread1 = INVALID_HANDLE_VALUE;
  11. HANDLE hThread2 = INVALID_HANDLE_VALUE;
  12. g_hEvent = CreateEvent(NULL, false, false, "Event");
  13. if (!g_hEvent)
  14. {
  15. cout << "Failed to CreateEvent !" << endl;
  16. return 0;
  17. }
  18. /*HANDLE CreateEvent(
  19. LPSECURITY_ATTRIBUTES lpEventAttributes,    // SECURITY_ATTRIBUTES结构指针,可为NULL
  20. BOOL bManualReset,                          // 手动/自动
  21.                                             // TRUE: 在WaitForSingleObject后必须手动调用ResetEvent清除信号
  22.     // FALSE:在WaitForSingleObject后,系统自动清除事件信号
  23. BOOL bInitialState,                         // 初始状态
  24. LPCTSTR lpName                              // 事件的名称
  25. );*/
  26. hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
  27. hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
  28. SetEvent(g_hEvent);
  29. Sleep(4000);        // 让2个线程有足够的时间执行完操作。
  30. CloseHandle(hThread1);
  31. CloseHandle(hThread2);
  32. system("PAUSE");
  33. return 0;
  34. }
  35. DWORD WINAPI Thread1(LPVOID lpParmeter)
  36. {
  37. while (true)
  38. {
  39. // 请求事件对象
  40. WaitForSingleObject(g_hEvent, INFINITE);    // INFINITE: 长时间等待,差不多50天左右吧!
  41. if (g_iCnt > 0)
  42. {
  43. Sleep(20);
  44. cout << "Thread1:" << g_iCnt-- << endl;
  45. SetEvent(g_hEvent);
  46. }
  47. else
  48. {
  49. SetEvent(g_hEvent);
  50. break;
  51. }
  52. }
  53. return 0;
  54. }
  55. DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
  56. {
  57. while (true)
  58. {
  59. // 请求事件对象
  60. WaitForSingleObject(g_hEvent,INFINITE);
  61. if (g_iCnt > 0)
  62. {
  63. Sleep(20);
  64. cout << "thread2:" << g_iCnt-- << endl;
  65. SetEvent(g_hEvent);
  66. }
  67. else
  68. {
  69. SetEvent(g_hEvent);
  70. break;
  71. }
  72. }
  73. return 0;
  74. }

几个注意的地方:

(1).和Mutex使用差不多,只有细微的差别;

(2).可以使用SetEvent或ResetEvent改变其状态;

(3).在应用程序中任意一处没有正确的按照规则调用SetEvent或ResetEvent,将达不到同步或互斥的目的;

(4).一般来说,都是利用Event来进行同步,而不是我们这里的让它来达到互斥;

(5).Event处于无信号状态时,相关线程或进程退出,系统并不会尝试将其置为有信号状态;

3.临界区 CRITICAL_SECTION

  1. #include <Windows.h>
  2. #include <iostream>
  3. using namespace std;
  4. DWORD WINAPI Thread1(LPVOID lpParmeter);
  5. DWORD WINAPI Thread2(LPVOID lpParmeter);
  6. CRITICAL_SECTION g_CriticalSection; // 定义
  7. static int g_iCnt = 100;
  8. int main()
  9. {
  10. HANDLE hThread1 = INVALID_HANDLE_VALUE;
  11. HANDLE hThread2 = INVALID_HANDLE_VALUE;
  12. InitializeCriticalSection(&g_CriticalSection);      // 初始化
  13. hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
  14. hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
  15. Sleep(4000);        // 让2个线程有足够的时间执行完操作。
  16. CloseHandle(hThread1);
  17. CloseHandle(hThread2);
  18. DeleteCriticalSection(&g_CriticalSection);          // 删除
  19. system("PAUSE");
  20. return 0;
  21. }
  22. DWORD WINAPI Thread1(LPVOID lpParmeter)
  23. {
  24. while (true)
  25. {
  26. EnterCriticalSection(&g_CriticalSection);       // 进入临界区,获得所有权,其他线程就等待
  27. if (g_iCnt > 0)
  28. {
  29. Sleep(20);
  30. cout << "Thread1:" << g_iCnt-- << endl;
  31. LeaveCriticalSection(&g_CriticalSection);   // 离开临界区,释放所有权
  32. }
  33. else
  34. {
  35. LeaveCriticalSection(&g_CriticalSection);
  36. break;
  37. }
  38. }
  39. return 0;
  40. }
  41. DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
  42. {
  43. while (true)
  44. {
  45. EnterCriticalSection(&g_CriticalSection);
  46. if (g_iCnt > 0)
  47. {
  48. Sleep(20);
  49. cout << "thread2:" << g_iCnt-- << endl;
  50. LeaveCriticalSection(&g_CriticalSection);
  51. }
  52. else
  53. {
  54. LeaveCriticalSection(&g_CriticalSection);
  55. break;
  56. }
  57. }
  58. return 0;
  59. }

几个注意的地方:

(1).比Mutex速度快;

(2).临界区在线程内的分配必须是全局的;

(3). 临界区一次只允许一个线程访问;

4.信号量Semaphore

首先说说那些关于信号量那些不得不让人伤心的事情,因为笔者大学不好学习,非常调皮,而信号量又是老师最讨论及考试的话题之一,所以我觉得这个东西非常扯淡,非常影响情绪,于是放在最后。------以上是为题外话。

为什么大学老师总是喜欢信号量呢?

因为这是一个生产者-消费者模型,并且很多计算机问题都可以看做是生产者-消费者的问题,是同步最易理解的模型。

关于理论上的知识,我就不说了,书里面很多的。

还有我不是很想实现生产者-消费者的模型,就用其他例子代替了。这个有点不负责任。

  1. #include <Windows.h>
  2. #include <iostream>
  3. #include <vector>
  4. using namespace std;
  5. DWORD WINAPI Thread1(LPVOID lpParmeter);
  6. DWORD WINAPI Thread2(LPVOID lpParmeter);
  7. static HANDLE g_hSemaphore = INVALID_HANDLE_VALUE;; // 定义
  8. static int g_iCnt = 100;
  9. int main()
  10. {
  11. HANDLE hThread1 = INVALID_HANDLE_VALUE;
  12. HANDLE hThread2 = INVALID_HANDLE_VALUE;
  13. // HANDLE CreateSemaphore (
  14. //  PSECURITY_ATTRIBUTE psa,
  15. //  LONG lInitialCount, //开始时可供使用的资源数
  16. //  LONG lMaximumCount, //最大资源数
  17. //  PCTSTR pszName);
  18. g_hSemaphore = CreateSemaphore(NULL, 1, 1, "Semaphore");
  19. // 初始化有1个信号量。
  20. if (g_hSemaphore == INVALID_HANDLE_VALUE)
  21. {
  22. cout << "Failed to Create Semaphore!" << endl;
  23. return 0;
  24. }
  25. hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
  26. hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
  27. Sleep(4000);        // 让2个线程有足够的时间执行完操作。
  28. CloseHandle(hThread1);
  29. CloseHandle(hThread2);
  30. system("PAUSE");
  31. return 0;
  32. }
  33. DWORD WINAPI Thread1(LPVOID lpParmeter)
  34. {
  35. while (true)
  36. {
  37. WaitForSingleObject(g_hSemaphore, INFINITE);        // 释放一个信号量
  38. if (g_iCnt > 0)
  39. {
  40. Sleep(20);
  41. cout << "Thread1:" << g_iCnt-- << endl;
  42. ReleaseSemaphore(g_hSemaphore, 1, NULL);        // 增加一个信号量
  43. }
  44. else
  45. {
  46. break;
  47. }
  48. }
  49. return 0;
  50. }
  51. DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
  52. {
  53. while (true)
  54. {
  55. WaitForSingleObject(g_hSemaphore, INFINITE);
  56. if (g_iCnt > 0)
  57. {
  58. Sleep(20);
  59. cout << "thread2:" << g_iCnt-- << endl;
  60. ReleaseSemaphore(g_hSemaphore, 1, NULL);
  61. }
  62. else
  63. {
  64. break;
  65. }
  66. }
  67. return 0;
  68. }

几个注意的地方:

信号量内核对象对线程的同步方式与前面几种不同,它允许多个线程在同一时刻访问某一资源,但是需要限制同一时刻访问此资源的最大线程数目。

总结: 线程规模 = CPU 数 * 2 + 1

Windows下C++多线程同步与互斥简单运用的更多相关文章

  1. Windows下C++多线程同步与互斥简单运用(转)

    1.  互斥量,Mutex #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ...

  2. 使用cwRsync实现windows下文件定时同步【转】

    1.参考文献: 使用cwRsync实现windows下文件定时同步(备份) 文件同步工具CwRsync的使用方法及常用命令详解 2.背景: 当前的SCADA架构中,有1台Server,5台FE,还有1 ...

  3. 使用cwRsync实现windows下文件定时同步

    1.参考文献: 使用cwRsync实现windows下文件定时同步(备份) 文件同步工具CwRsync的使用方法及常用命令详解 2.背景: 当前的SCADA架构中,有1台Server,5台FE,还有1 ...

  4. C#Stimulator项目>>>C/C++ DLL的生成和调用,Windows下的多线程

    Windows下的多线程 http://blog.csdn.net/ganpengjin1/article/category/2541791 使用C/C++建立DLL,环境VS2013 新建Win32 ...

  5. Windows下安装Redis服务、搭建简单Redis主从复制

    Redis拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构.目前在同一台window下安装三个r ...

  6. Windows 下针对python脚本做一个简单的进程保护

    前提: 大家运行的脚本程序经常会碰到系统异常关闭.或被其他用户错杀的情况.这样就需要一个进程保护的工具. 本文结合windows 的计划任务,实现一个简单的进程保护的功能. 利用py2exe生产 ex ...

  7. Windows下的多线程

    Windows下的进程和Linux下的进程是不一样的,它比较懒惰,从来不执行任何东西,它只是为线程提供执行环境,然后由线程负责执行包含在进程的地址空间中的代码.当创建一个进程的时候,操作系统会自动创建 ...

  8. windows 下的 Rsync 同步

    整理一下 windows 下的 rsync 文件同步. Rsync下载地址: 链接:https://pan.baidu.com/s/1nL0Ee_u76ytWKUFMeiKDIw 提取码:52in 一 ...

  9. Windows下PHP多线程扩展pthreads的安装

    pthreads扩展安装步骤 1.查看phpinfo() 获取PHP版本号及位数(x86表示32位,x64表示64位).编译器版本.PHP配置文件加载所在位置等.如下图所示: 2.pthreads扩展 ...

随机推荐

  1. 浅析C# 中object sender与EventArgs e (转)

    一.了解C#中的预定义事件处理机制    在写代码前我们先来熟悉.net框架中和事件有关的类和委托,了解C#中预定义事件的处理. EventArgs是包含事件数据的类的基类,用于传递事件的细节. Ev ...

  2. RCTF Welpwn

    Welpwn 很久以前的了,现在整理一下 题目的漏洞很明显,就是一个栈溢出.程序打开了NX,却没有给libc.重点是,在向栈上拷贝数据时,如果输入中含有'\x00',会被截断,对利用漏洞造成了困难.虽 ...

  3. 从头开始-05.C语言中函数

    函数: 完成特定功能代码段 特点:函数只有调用的时候才会执行 定义格式:返回值类型 函数名称(形参类型 形参名称,...){ 语句; ...  } 函数参数 形式参数:在定义函数的时候,函数名后面小括 ...

  4. C#核编之格式化编程

    一.格式化控制台输入输出 1. 在前面的随笔中,会经常看到诸如{0},{1}之类的标记嵌入在字符串变量中..NET引入一种字符串格式化的新风格.与C的printf()相似,简而言之,如果需要定义一个字 ...

  5. ExecutorService 的理解与使用

    ExecutorService 的理解与使用  http://my.oschina.net/bairrfhoinn/blog/177639 Java线程池ExecutorService http:// ...

  6. discuz二次开发笔记(一)------$_G全解析

    $_G 保存了 Discuz! 中所有的预处理数据缓存能够很好的提高程序的性能,一些配置数据没必要每次都查询数据库,只要在修改了的时候更新下缓存即可.Discuz! 中所有的缓存保存在 $_G[cac ...

  7. 【学习笔记01】:hover为DIV添加鼠标悬停时改变颜色的效果

    :hover所有主流浏览器都支持(IE6.0以下支持不好,以后再学习用Javascript来实现悬停效果) 这是一个绿色底白色Icon的搜索按钮

  8. linux 生产环境搭建

    Linux基础命令杂记   今天又一次搞Linux生产环境搭建.这是种步骤很多,很繁琐而且又不得不做的事情.虽然做过很多次,但还是有很多步骤.命令不记得,每一次到处找资料很麻烦,于是将一些步骤记下,以 ...

  9. SurfaceView绘图机制

    一.为什么需要用SurfaceView绘图,不直接继承View绘图 它的特性是:可以在主线程之外的线程中向屏幕绘图上.这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度.在游戏开发 ...

  10. android xml解析 sax

    1.简要概述 Android 各种文件都是xml格式的,还有标准的webservice返回的是xml文件,虽然现在的json使用在移动设备端越来越广泛,但是xml格式的解析感觉还是相当必要. 2.sa ...