我们对线程做一些简单的同步处理,这里我们用互斥量(Mutex)。

互斥量(Mutex)和二元信号量类似,资源仅允许一个线程访问。与二元信号量不同的是,信号量在整个系统中可以被任意线程获取和释放,也就是说,同一个信号量可以由一个线程获取而由另一线程释放。而互斥量则要求哪个线程获取了该互斥量锁就由哪个线程释放,其它线程越俎代庖释放互斥量是无效的。

在使用互斥量进行线程同步时会用到以下几个函数:

HANDLE WINAPI CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,        //线程安全相关的属性,常置为NULLBOOL                  bInitialOwner,            //创建Mutex时的当前线程是否拥有Mutex的所有权LPCTSTR               lpName                    //Mutex的名称
);

说明: lpMutexAttributes也是表示安全的结构,与CreateThread中的lpThreadAttributes功能相同,表示决定返回的句柄是否可被子进程继承,如果为NULL则表示返回的句柄不能被子进程继承。bInitialOwner表示创建Mutex时的当前线程是否拥有Mutex的所有权,若为TRUE则指定为当前的创建线程为Mutex对象的所有者,其它线程访问需要先ReleaseMutex。lpName为Mutex的名称。

DWORD WINAPI WaitForSingleObject(HANDLE hHandle,                             //要获取的锁的句柄DWORD  dwMilliseconds                           //超时间隔
);

说明: WaitForSingleObject的作用是等待一个指定的对象(如Mutex对象),直到该对象处于非占用的状态(如Mutex对象被释放)或超出设定的时间间隔。除此之外,还有一个与它类似的函数WaitForMultipleObjects,它的作用是等待一个或所有指定的对象,直到所有的对象处于非占用的状态,或超出设定的时间间隔。

hHandle:要等待的指定对象的句柄。dwMilliseconds:超时的间隔,以毫秒为单位;如果dwMilliseconds为非0,则等待直到dwMilliseconds时间间隔用完或对象变为非占用的状态,如果dwMilliseconds 为INFINITE则表示无限等待,直到等待的对象处于非占用的状态。

BOOL WINAPI ReleaseMutex(HANDLE hMutex);

说明:释放所拥有的互斥量锁对象,hMutex为释放的互斥量的句柄。

#include "stdafx.h"
#include <windows.h>
#include <iostream>#define NAME_LINE   40//定义线程函数传入参数的结构体
typedef struct __THREAD_DATA
{int nMaxNum;char strThreadName[NAME_LINE];__THREAD_DATA() : nMaxNum(0){memset(strThreadName, 0, NAME_LINE * sizeof(char));}
}THREAD_DATA;HANDLE g_hMutex = NULL;     //互斥量//线程函数
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{THREAD_DATA* pThreadData = (THREAD_DATA*)lpParameter;for (int i = 0; i < pThreadData->nMaxNum; ++ i){//请求获得一个互斥量锁WaitForSingleObject(g_hMutex, INFINITE);cout << pThreadData->strThreadName << " --- " << i << endl;Sleep(100);//释放互斥量锁ReleaseMutex(g_hMutex);}return 0L;
}int main()
{//创建一个互斥量g_hMutex = CreateMutex(NULL, FALSE, NULL);//初始化线程数据THREAD_DATA threadData1, threadData2;threadData1.nMaxNum = 5;strcpy(threadData1.strThreadName, "线程1");threadData2.nMaxNum = 10;strcpy(threadData2.strThreadName, "线程2");//创建第一个子线程HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc, &threadData1, 0, NULL);//创建第二个子线程HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc, &threadData2, 0, NULL);//关闭线程CloseHandle(hThread1);CloseHandle(hThread2);//主线程的执行路径for (int i = 0; i < 5; ++ i){//请求获得一个互斥量锁WaitForSingleObject(g_hMutex, INFINITE);cout << "主线程 === " << i << endl;Sleep(100);//释放互斥量锁ReleaseMutex(g_hMutex);}system("pause");return 0;
}

结果:

主线程 === 0
线程1 — 0
线程2 — 0
主线程 === 1
线程1 — 1
线程2 — 1
主线程 === 2
线程1 — 2
线程2 — 2
主线程 === 3
线程1 — 3
线程2 — 3
主线程 === 4
线程1 — 4
请按任意键继续… 线程2 — 4
线程2 — 5
线程2 — 6
线程2 — 7
线程2 — 8
线程2 — 9
为进一步理解线程同步的重要性和互斥量的使用方法,我们再来看一个例子。

买火车票是大家春节回家最为关注的事情,我们就简单模拟一下火车票的售票系统(为使程序简单,我们就抽出最简单的模型进行模拟):有500张从北京到赣州的火车票,在8个窗口同时出售,保证系统的稳定性和数据的原子性。

【Demo4】:模拟火车售票系统
SaleTickets.h

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <strstream>
#include <string>using namespace std;#define NAME_LINE   40//定义线程函数传入参数的结构体
typedef struct __TICKET
{int nCount;char strTicketName[NAME_LINE];__TICKET() : nCount(0){memset(strTicketName, 0, NAME_LINE * sizeof(char));}
}TICKET;typedef struct __THD_DATA
{TICKET* pTicket;char strThreadName[NAME_LINE];__THD_DATA() : pTicket(NULL){memset(strThreadName, 0, NAME_LINE * sizeof(char));}
}THD_DATA;//基本类型数据转换成字符串
template<class T>
string convertToString(const T val)
{string s;std::strstream ss;ss << val;ss >> s;return s;
}//售票程序
DWORD WINAPI SaleTicket(LPVOID lpParameter);

SaleTickets.cpp

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include "SaleTickets.h"using namespace std;extern HANDLE g_hMutex;//售票程序
DWORD WINAPI SaleTicket(LPVOID lpParameter)
{THD_DATA* pThreadData = (THD_DATA*)lpParameter;TICKET* pSaleData = pThreadData->pTicket;while(pSaleData->nCount > 0){//请求获得一个互斥量锁WaitForSingleObject(g_hMutex, INFINITE);if (pSaleData->nCount > 0){cout << pThreadData->strThreadName << "出售第" << pSaleData->nCount -- << "的票,";if (pSaleData->nCount >= 0) {cout << "出票成功!剩余" << pSaleData->nCount << "张票." << endl;} else {cout << "出票失败!该票已售完。" << endl;}}Sleep(10);//释放互斥量锁ReleaseMutex(g_hMutex);}return 0L;
}

测试程序:

//售票系统
void Test2()
{//创建一个互斥量g_hMutex = CreateMutex(NULL, FALSE, NULL);//初始化火车票TICKET ticket;ticket.nCount = 100;strcpy(ticket.strTicketName, "北京-->赣州");const int THREAD_NUMM = 8;THD_DATA threadSale[THREAD_NUMM];HANDLE hThread[THREAD_NUMM];for(int i = 0; i < THREAD_NUMM; ++ i){threadSale[i].pTicket = &ticket;string strThreadName = convertToString(i);strThreadName = "窗口" + strThreadName;strcpy(threadSale[i].strThreadName, strThreadName.c_str());//创建线程hThread[i] = CreateThread(NULL, NULL, SaleTicket, &threadSale[i], 0, NULL);//请求获得一个互斥量锁WaitForSingleObject(g_hMutex, INFINITE);cout << threadSale[i].strThreadName << "开始出售 " << threadSale[i].pTicket->strTicketName << " 的票..." << endl;//释放互斥量锁ReleaseMutex(g_hMutex);//关闭线程CloseHandle(hThread[i]);}system("pause");
}

结果:

窗口0开始出售 北京–>赣州 的票…
窗口0出售第100的票,出票成功!剩余99张票.
窗口1开始出售 北京–>赣州 的票…
窗口1出售第99的票,出票成功!剩余98张票.
窗口0出售第98的票,出票成功!剩余97张票.
窗口2开始出售 北京–>赣州 的票…
窗口2出售第97的票,出票成功!剩余96张票.
窗口1出售第96的票,出票成功!剩余95张票.
窗口0出售第95的票,出票成功!剩余94张票.
窗口3开始出售 北京–>赣州 的票…
窗口3出售第94的票,出票成功!剩余93张票.
窗口2出售第93的票,出票成功!剩余92张票.
窗口1出售第92的票,出票成功!剩余91张票.
窗口0出售第91的票,出票成功!剩余90张票.
窗口4开始出售 北京–>赣州 的票…
窗口4出售第90的票,出票成功!剩余89张票.
窗口3出售第89的票,出票成功!剩余88张票.
窗口2出售第88的票,出票成功!剩余87张票.
窗口1出售第87的票,出票成功!剩余86张票.
窗口0出售第86的票,出票成功!剩余85张票.
窗口5开始出售 北京–>赣州 的票…
窗口5出售第85的票,出票成功!剩余84张票.
窗口4出售第84的票,出票成功!剩余83张票.
窗口3出售第83的票,出票成功!剩余82张票.
窗口2出售第82的票,出票成功!剩余81张票.

CreateMutex、WaitForSingleObject、ReleaseMutex相关推荐

  1. CreateMutex、WaitForSingleObject、ReleaseMutex——创建互斥对象

    CreateMutex CreateMutex作用是找出当前系统是否已经存在指定进程的实例.如果没有则创建一个互斥体. 互斥对象是系统内核维护的一种数据结构,它保证了对象对单个线程的访问权 互斥对象的 ...

  2. 多线程编程里如何运用CreateMutex,WaitForSingleObject,ReleaseMutex来实现线程同步

    这几天忙着写一个实现basler相机的采集功能的软件,其实无非也就是看文档,调用他提供的接口. 但在这其中出现了一点小问题,我写了一个子进程,但每次使用全局标识符关闭子进程,主进程都会出现错误,提示捕 ...

  3. Windows线程CreateThread、线程处理函数、SuspendThread、ResumeThread、WaitForSingleObject、WaitForMultipleObjects

    Windows线程是可以执行的代码的实例.系统是以线程为单位调度程序.一个程序当中可以有多个线程,实现多任务的处理. windows线程的特点: 1.线程都具有一个ID 2.每个线程都具有自己的内存栈 ...

  4. linux 线程 waitforsingleobject,WaitForSingleObject、WaitForMulitpleObjects和SignalObjectAndWait线程同步...

    WaitForSingleObject.WaitForMulitpleObjects和SignalObjectAndWait线程同步 2010-12-10 15:47 类型:生活点滴 用户模式的线程同 ...

  5. 线程中CreateEvent、SetEvent、WaitForSingleObject的用法

    原文地址:https://www.cnblogs.com/MrYuan/p/5238749.html 首先介绍CreateEvent是创建windows事件的意思,作用主要用在判断线程退出,线程锁定方 ...

  6. CMutex、CCriticalSection、CSemaphore、CEvent、WaitForSingleObject 的小例子

    一.CMutex CMutex mutex; mutex.Lock(); // 互斥的动作 // mutex.Unlock(); 二.CCriticalSection CCriticalSection ...

  7. FatFs 之一 R0.13c版源码目录文件、函数、全配置项详解及移植说明

      FatFs 是用于小型嵌入式系统的通用 FAT/exFAT 文件系统模块.FatFs 模块的编写符合 ANSI C(C89),并与磁盘 I/O 层完全分离,因此它独立于硬件平台. 它可以集成到资源 ...

  8. 线程同步(临界区、互斥量、事件、信号量)

    1.为什么线程要同步? #include<windows.h> #include<iostream> using namespace std; DWORD WINAPI Thr ...

  9. 进程与线程(同步、互斥、通信方式等)

    一.并发 并行 同步 异步 多线程的区别(引用:https://blog.csdn.net/cqkxboy168/article/details/9026205) 1. 并发:在操作系统中,是指一个时 ...

最新文章

  1. AEAI WM v1.6.0 升级说明,开源工作管理系统
  2. YIFullScreenScroll
  3. sqlserver 分页存储过程
  4. idea中怎么忽略(ignore)掉 .idea等文件
  5. C# 依据KeyEventArgs与组合键字符串相互转换
  6. 《深入浅出DPDK》读书笔记(十四):DPDK应用篇(DPDK与网络功能虚拟化:NFV、VNF、IVSHMEM、Virtual BRAS“商业案例”)
  7. 软件测试需注意的事项
  8. php代码实现文件下载,php实现文件下载的简单代码
  9. 第一次c++上机实验
  10. 把CSV文件导入到MySQL数据库中
  11. VS提示error C2011: “timespec”:“struct”类型重定义
  12. WEB前端(4)—— CSS经典案例(DIV+CSS布局)
  13. vs2010专业版下载链接
  14. 直方图代码matlab,MATLAB直方图均衡化代码(MATLAB histogram equalization code).doc
  15. 【离散数学】二元关系中的自反闭包,对称闭包,传递闭包
  16. ajax 发http请求吗,使用 Ajax 发送 http 请求 (getpost 请求)
  17. jcp jsr_JCP选举结果:LJC和CloudBees赢得EC席位
  18. OpenREALM :基于视觉SLAM和三维重建的无人机实时空中测绘
  19. 自定义协议的命令解析器
  20. VCC VDD, VEE, VSS是什么意思

热门文章

  1. 数据结构系列之基础篇(一)数据与结构
  2. 如何将自身的商标从“知产”转变为“资产”?
  3. Linux nice及renice命令使用
  4. 如何验证云服务器网络带宽?
  5. MySql学习系列(一)
  6. linux 目录结构_Linux目录结构,解释
  7. 新Java运动Nava:师PHP技术以开发Web应用
  8. 2012 android开发工具,2012最新完整版Android开发入门教程
  9. android 12.0屏蔽系统所有通知
  10. 宁夏有计算机二级access考试内容,2015宁夏回族自治区计算机等级考试试题 二级ACCESS考资料...