Windows下C++多线程同步与互斥简单运用
1. 互斥量,Mutex
- #include <Windows.h>
- #include <iostream>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- static HANDLE g_hMutex = INVALID_HANDLE_VALUE;
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- g_hMutex = CreateMutex(NULL, FALSE, "Mutex");
- // 第二个参数:创建者是否拥有所有权,FALSE为没有所有权,
- // 遇到第一个WaitForSingleObject的时候就把所有权给它,
- // 所以Thread1里面的WaitForSingleObject(g_hMutex, INFINITE)能够继续执行
- if (!g_hMutex)
- {
- cout << "Failed to CreateMutex !" << endl;
- return 0;
- }
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- Sleep(4000); // 让2个线程有足够的时间执行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- // 请求事件对象
- WaitForSingleObject(g_hMutex, INFINITE); // INFINITE: 长时间等待,差不多50天左右吧!
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- ReleaseMutex(g_hMutex); // 释放资源
- }
- else
- {
- ReleaseMutex(g_hMutex);
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- // 请求事件对象
- WaitForSingleObject(g_hMutex,INFINITE);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- ReleaseMutex(g_hMutex);
- }
- else
- {
- ReleaseMutex(g_hMutex);
- break;
- }
- }
- return 0;
- }
几个注意的地方:
(1)互斥量为内核对象,能够与其他线程或特殊事件取得同步;
(2)速度比临界区要慢;
(3)互斥量对象与所有其它内核对象的不同之处在于它是被线程所拥有的,互斥量对象除了记录当前信号状态外,还要记住此时那个线程拥有它。
(4)这个常来被运用于限制程序启动次数!
2.事件 Event
- #include <Windows.h>
- #include <iostream>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- static HANDLE g_hEvent = INVALID_HANDLE_VALUE;
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- g_hEvent = CreateEvent(NULL, false, false, "Event");
- if (!g_hEvent)
- {
- cout << "Failed to CreateEvent !" << endl;
- return 0;
- }
- /*HANDLE CreateEvent(
- LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL
- BOOL bManualReset, // 手动/自动
- // TRUE: 在WaitForSingleObject后必须手动调用ResetEvent清除信号
- // FALSE:在WaitForSingleObject后,系统自动清除事件信号
- BOOL bInitialState, // 初始状态
- LPCTSTR lpName // 事件的名称
- );*/
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- SetEvent(g_hEvent);
- Sleep(4000); // 让2个线程有足够的时间执行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- // 请求事件对象
- WaitForSingleObject(g_hEvent, INFINITE); // INFINITE: 长时间等待,差不多50天左右吧!
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- SetEvent(g_hEvent);
- }
- else
- {
- SetEvent(g_hEvent);
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- // 请求事件对象
- WaitForSingleObject(g_hEvent,INFINITE);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- SetEvent(g_hEvent);
- }
- else
- {
- SetEvent(g_hEvent);
- break;
- }
- }
- return 0;
- }
几个注意的地方:
(1).和Mutex使用差不多,只有细微的差别;
(2).可以使用SetEvent或ResetEvent改变其状态;
(3).在应用程序中任意一处没有正确的按照规则调用SetEvent或ResetEvent,将达不到同步或互斥的目的;
(4).一般来说,都是利用Event来进行同步,而不是我们这里的让它来达到互斥;
(5).Event处于无信号状态时,相关线程或进程退出,系统并不会尝试将其置为有信号状态;
3.临界区 CRITICAL_SECTION
- #include <Windows.h>
- #include <iostream>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- CRITICAL_SECTION g_CriticalSection; // 定义
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- InitializeCriticalSection(&g_CriticalSection); // 初始化
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- Sleep(4000); // 让2个线程有足够的时间执行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- DeleteCriticalSection(&g_CriticalSection); // 删除
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- EnterCriticalSection(&g_CriticalSection); // 进入临界区,获得所有权,其他线程就等待
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- LeaveCriticalSection(&g_CriticalSection); // 离开临界区,释放所有权
- }
- else
- {
- LeaveCriticalSection(&g_CriticalSection);
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- EnterCriticalSection(&g_CriticalSection);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- LeaveCriticalSection(&g_CriticalSection);
- }
- else
- {
- LeaveCriticalSection(&g_CriticalSection);
- break;
- }
- }
- return 0;
- }
几个注意的地方:
(1).比Mutex速度快;
(2).临界区在线程内的分配必须是全局的;
(3). 临界区一次只允许一个线程访问;
4.信号量Semaphore
首先说说那些关于信号量那些不得不让人伤心的事情,因为笔者大学不好学习,非常调皮,而信号量又是老师最讨论及考试的话题之一,所以我觉得这个东西非常扯淡,非常影响情绪,于是放在最后。------以上是为题外话。
为什么大学老师总是喜欢信号量呢?
因为这是一个生产者-消费者模型,并且很多计算机问题都可以看做是生产者-消费者的问题,是同步最易理解的模型。
关于理论上的知识,我就不说了,书里面很多的。
还有我不是很想实现生产者-消费者的模型,就用其他例子代替了。这个有点不负责任。
- #include <Windows.h>
- #include <iostream>
- #include <vector>
- using namespace std;
- DWORD WINAPI Thread1(LPVOID lpParmeter);
- DWORD WINAPI Thread2(LPVOID lpParmeter);
- static HANDLE g_hSemaphore = INVALID_HANDLE_VALUE;; // 定义
- static int g_iCnt = 100;
- int main()
- {
- HANDLE hThread1 = INVALID_HANDLE_VALUE;
- HANDLE hThread2 = INVALID_HANDLE_VALUE;
- // HANDLE CreateSemaphore (
- // PSECURITY_ATTRIBUTE psa,
- // LONG lInitialCount, //开始时可供使用的资源数
- // LONG lMaximumCount, //最大资源数
- // PCTSTR pszName);
- g_hSemaphore = CreateSemaphore(NULL, 1, 1, "Semaphore");
- // 初始化有1个信号量。
- if (g_hSemaphore == INVALID_HANDLE_VALUE)
- {
- cout << "Failed to Create Semaphore!" << endl;
- return 0;
- }
- hThread1 = CreateThread(NULL, 0, Thread1, NULL, 0, NULL);
- hThread2 = CreateThread(NULL, 0, Thread2, NULL, 0, NULL);
- Sleep(4000); // 让2个线程有足够的时间执行完操作。
- CloseHandle(hThread1);
- CloseHandle(hThread2);
- system("PAUSE");
- return 0;
- }
- DWORD WINAPI Thread1(LPVOID lpParmeter)
- {
- while (true)
- {
- WaitForSingleObject(g_hSemaphore, INFINITE); // 释放一个信号量
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "Thread1:" << g_iCnt-- << endl;
- ReleaseSemaphore(g_hSemaphore, 1, NULL); // 增加一个信号量
- }
- else
- {
- break;
- }
- }
- return 0;
- }
- DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
- {
- while (true)
- {
- WaitForSingleObject(g_hSemaphore, INFINITE);
- if (g_iCnt > 0)
- {
- Sleep(20);
- cout << "thread2:" << g_iCnt-- << endl;
- ReleaseSemaphore(g_hSemaphore, 1, NULL);
- }
- else
- {
- break;
- }
- }
- return 0;
- }
几个注意的地方:
信号量内核对象对线程的同步方式与前面几种不同,它允许多个线程在同一时刻访问某一资源,但是需要限制同一时刻访问此资源的最大线程数目。
总结: 线程规模 = CPU 数 * 2 + 1
Windows下C++多线程同步与互斥简单运用的更多相关文章
- Windows下C++多线程同步与互斥简单运用(转)
1. 互斥量,Mutex #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ...
- 使用cwRsync实现windows下文件定时同步【转】
1.参考文献: 使用cwRsync实现windows下文件定时同步(备份) 文件同步工具CwRsync的使用方法及常用命令详解 2.背景: 当前的SCADA架构中,有1台Server,5台FE,还有1 ...
- 使用cwRsync实现windows下文件定时同步
1.参考文献: 使用cwRsync实现windows下文件定时同步(备份) 文件同步工具CwRsync的使用方法及常用命令详解 2.背景: 当前的SCADA架构中,有1台Server,5台FE,还有1 ...
- C#Stimulator项目>>>C/C++ DLL的生成和调用,Windows下的多线程
Windows下的多线程 http://blog.csdn.net/ganpengjin1/article/category/2541791 使用C/C++建立DLL,环境VS2013 新建Win32 ...
- Windows下安装Redis服务、搭建简单Redis主从复制
Redis拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构.目前在同一台window下安装三个r ...
- Windows 下针对python脚本做一个简单的进程保护
前提: 大家运行的脚本程序经常会碰到系统异常关闭.或被其他用户错杀的情况.这样就需要一个进程保护的工具. 本文结合windows 的计划任务,实现一个简单的进程保护的功能. 利用py2exe生产 ex ...
- Windows下的多线程
Windows下的进程和Linux下的进程是不一样的,它比较懒惰,从来不执行任何东西,它只是为线程提供执行环境,然后由线程负责执行包含在进程的地址空间中的代码.当创建一个进程的时候,操作系统会自动创建 ...
- windows 下的 Rsync 同步
整理一下 windows 下的 rsync 文件同步. Rsync下载地址: 链接:https://pan.baidu.com/s/1nL0Ee_u76ytWKUFMeiKDIw 提取码:52in 一 ...
- Windows下PHP多线程扩展pthreads的安装
pthreads扩展安装步骤 1.查看phpinfo() 获取PHP版本号及位数(x86表示32位,x64表示64位).编译器版本.PHP配置文件加载所在位置等.如下图所示: 2.pthreads扩展 ...
随机推荐
- css中关于transform、transition、animate的区别
写动画经常会用到这几个属性,他们之间有什么区别呢? 1.transform 每每演示transform属性的,看起来好像都是带动画.这使得小部分直觉化思维的人(包括我)认为transform属性是动画 ...
- Meta标签中的apple-mobile-web-app-capable属性及含义
这meta的作用就是删除默认的苹果工具栏和菜单栏. content有两个值”yes”和”no”,当我们需要显示工具栏和菜单栏时,这个行meta就不用加了,默认就是显示.
- C#识别图片上的数字
通过Emgu实现对图片上的数字进行识别. 前期步骤: 1.下载Emgu安装文件,我的版本是2.4.2.1777.3.0版本则实现对中文的支持. 2.安装后需填写环境变量,环境变量Path值后加入Emg ...
- effective c++ 条款06 不想自动生成函数,就明确拒绝
编辑器会主动的生成三个/五个函数,如果不需要我们应该主动拒绝 使用私有属性来拒绝 ``` include int main() { return 0; } ``` 使用继承的方式来拒绝
- python程序不支持中文
SyntaxError: Non-ASCII character '\xe8' in file delete.py on line 4, but no encoding declared; see h ...
- oracle中sql查询语句的执行顺序
查询语句的处理过程主要包含3个阶段:编译.执行.提取数据(sql查询语句的处理主要是由用户进程和服务器进程完成的,其他进程辅助配合) 一.编译parse 在进行编译时服务器进程会将sql语句的正文放入 ...
- Android Canvas不能换行,或者不识别\n,\r\n的解决方案
在使用Canvas绘制文本的时候,如果要绘制的字符串含有\r\n,\n换行的时候,会识别不出来,当成空格绘制出来. 解决方案: 1.使用StaticLayout来实现,具体代码如下: TextPain ...
- MySQL表结构同步工具 mysql-schema-sync
mysql-schema-sync 是一款使用go开发的.跨平台的.绿色无依赖的 MySQL 表结构自动同步工具.用于将线上(其他环境)数据库结构变化同步到测试(本地)环境! 可以解决多人开发,每人都 ...
- return 和 echo 的小坑
在写项目的时候,有好几次遇到过同样的问题,控制器里面返回的json在前台无显示,利用console.log()总是显示这样的现象 数据库操作成功,却没有返回值. 原因是在控制器返回的使用使用了 ret ...
- 初学swift笔记 函数(六)
import Foundation /* func 函数名 (参数名:参数类型) { } func 函数名 (参数名:参数类型) ->Void{ } func 函数名 (参数名:参数类型) -& ...