一、互斥锁

1、先熟悉熟悉API

1,创建互斥锁,并反正一个句柄
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESlpMutexAttributes, // 指向安全属性的指针
BOOLbInitialOwner, // 初始化互斥对象的所有者,一般设置为FALSE
LPCTSTRlpName // 互斥对象名
);2,释放互斥对象的控制权
BOOL ReleaseMutex(
HANDLE hMutex //已创建Mutex的句柄
);3,打开互斥锁,返回句柄
HANDLE OpenMutex(
DWORDdwDesiredAccess, // 互斥体的访问权限
BOOLbInheritHandle, //如希望子进程能够继承句柄,则为TRUE
LPCTSTRlpName // 互斥锁名字
);4,等待目标返回
DWORD WaitForSingleObject(
HANDLE hHandle, //目标句柄
DWORD dwMilliseconds //等待时间 ,毫秒记,INFINITE为永久等待
);

一个简单的互斥锁例子来实现多线程同步

#include<Windows.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
static int g_count = 100;class Lock
{
public:Lock(char*szName){hd = OpenMutex(MUTEX_ALL_ACCESS, NULL, (LPCWSTR)szName);WaitForSingleObject(hd, INFINITE);Sleep(1500);//测试用:等待1.5秒,正式类中不应有}~Lock(){ReleaseMutex(hd);}static bool InitLock(char*szName){if (!OpenMutex(MUTEX_ALL_ACCESS, NULL, (LPCWSTR)szName)){if (!CreateMutex(NULL, NULL, (LPCWSTR)szName))return false;return true;}return false;}HANDLE hd;
};UINT address1(LPVOID lparam)
{while (1){Lock lc("_temp_lock");cout << g_count-- << "---" << "address1" << endl;}
}UINT address2(LPVOID lparam)
{while (1){Lock lc("_temp_lock");cout << g_count-- << "---" << "address2" << endl;}
}
int main(int argc, char*argv[])
{if(!Lock::InitLock("_temp_lock"))//创建互斥锁失败return -1;CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2system("pause");return 0;
}

原理浅析:Lock::InitLock()来创建互斥锁,在本demo中,同步是按照CreateThread的创建顺序。创建了一个Lock类,当生成对象的时候就等待,一旦当互斥锁没有控制权,等待即结束,便向下执行,对象析构的时候就释放控制权,以此类推循环。
ps:mutex作用范围在系统层,使用mutex效率并不是太高,使用临界区(作用范围在进程)效率比较高



二、信号量

1,先熟悉熟悉API

CreateSemaphore() 创建一个信号量  OpenSemaphore() 打开一个信号量  ReleaseSemaphore() 释放信号量 WaitForSingleObject() 等待信号量  

2,举个简单的小例子

#include <stdio.h>
#include <Windows.h>  #define THREAD_NUM 20
#define SEM_NAME "THREAD_SEMAPHORE"HANDLE g_hSem = NULL;
HANDLE g_hThread[THREAD_NUM];void WINAPI ThreadFun(void* param)
{printf("进入线程: %u,并等待\n", GetCurrentThreadId());WaitForSingleObject(g_hSem, INFINITE);printf("线程: %u 获得信号量\n", GetCurrentThreadId());long dwSem = 0;if (!ReleaseSemaphore(g_hSem, 1, &dwSem))return;printf("目前资源数:%u\n", dwSem);
}int  main(int argc, char*argv[])
{g_hSem = CreateSemaphoreA(NULL, 0, 5, SEM_NAME);g_hSem = OpenSemaphoreA(SEMAPHORE_MODIFY_STATE, FALSE, SEM_NAME);for (int i = 0; i < THREAD_NUM; ++i){DWORD dwThreadID = 0;g_hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, NULL, 0, &dwThreadID);}WaitForMultipleObjects(THREAD_NUM, g_hThread, TRUE, INFINITE);printf("全部执行完了\n");return 0;
}

ps:信号量可以说在平常的使用中用的比较少,一般的用途在控制并发线程数量,抢占资源问题。



三、事件

1,先熟悉熟悉API

HANDLE CreateEvent( //创建事件
LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性
BOOL bManualReset,// 复位方式
BOOL bInitialState,// 初始状态
LPCTSTR lpName // 对象名称
);HANDLE OpenEvent( //打开事件
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCTSTR lpName
);BOOL ResetEvent(//事件对象设置为无信号状态。
HANDLE hEvent
);BOOL SetEvent(HANDLE hEvent);//事件对象设置为有信号状态。 BOOL PulseEvent(HANDLE hEvent)//事件对象设置为有信号状态,脉冲一个事件WaitForSingleObject() 等待信号量  

2,举个简单的小例子

#include <stdio.h>
#include <Windows.h>
HANDLE g_hEvent;UINT address1(LPVOID lparam)
{printf("进入线程了,等待5秒\n");WaitForSingleObject(g_hEvent, INFINITE);printf("等待结束了,向下执行了!\n");return 0;
}UINT address2(LPVOID lparam)
{Sleep(5000);SetEvent(g_hEvent);return 0;
}int main(int argc, char*argv[])
{g_hEvent=CreateEvent(NULL, true, FALSE, NULL);ResetEvent(g_hEvent);CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2system("pause");return 0;
}

ps:本小例模拟了的两个线程间的同步,address2来控制address1的执行,事件在多线程程序中的应用比较多,比较重要,定要熟练掌握。



四、临界区

1,先熟悉熟悉API

void InitializeCriticalSection(//初始化临界区LPCRITICAL_SECTION lpCriticalSection); void WINAPI DeleteCriticalSection( //删除临界区
_Inout_ LPCRITICAL_SECTION lpCriticalSection);VOID WINAPI EnterCriticalSection( //进入临界区  __inout LPCRITICAL_SECTION lpCriticalSection
); VOID WINAPI LeaveCriticalSection(//离开临界区_Inout_ LPCRITICAL_SECTION lpCriticalSection);

2,举个简单的小例子

#include <stdio.h>
#include <Windows.h>CRITICAL_SECTION g_cs;
int g_nIndex = 20;UINT address1(LPVOID lparam)
{while(true){if (10 == g_nIndex)return 1;EnterCriticalSection(&g_cs);printf("address111线程,index=%d\n",g_nIndex);g_nIndex--;LeaveCriticalSection(&g_cs);}return 0;}UINT address2(LPVOID lparam)
{while (true){if (0 == g_nIndex)return 1;EnterCriticalSection(&g_cs);printf("address222线程,index=%d\n", g_nIndex);--g_nIndex;LeaveCriticalSection(&g_cs);}return 0;
}
int main(int argc, char*argv[])
{InitializeCriticalSection(&g_cs);CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2system("pause");DeleteCriticalSection(&g_cs);return 0;
}

ps:小例中,address1被临界区一直占用到到address1退出,address2才能进入临界区,进行直到退出,与mutex交替执行不同,临界区比较简单且最易用。


更多文章:http://blog.csdn.net/what951006?viewmode=list
powered by:小乌龟在大乌龟背上~

C++多线程 互斥锁 信号量 事件 临界区相关推荐

  1. java多线程互斥锁_浅谈Java多线程互斥锁

    为了解决竞争条件带来的问题,我们可以对资源上锁.多个线程共同读写的资源称为共享资源,也叫临界资源.涉及操作临界资源的代码区域称为临界区(Critical Section).同一时刻,只能有一个线程进入 ...

  2. java多线程- 互斥锁 自旋锁

    如果一个资源会被不同的线程访问修改,那么我们把这个资源叫做临界资源(<操作系统>),那么对于该资源访问修改相关的代码就叫做临界区.引入互斥锁即解决多个线程之间共享同一个共享资源,这是多线程 ...

  3. 进程同步控制(锁,信号量,事件), 进程通讯(队列和管道,生产者消费者模型) 数据共享(进程池和mutiprocess.Pool模块)...

    参考博客 https://www.cnblogs.com/xiao987334176/p/9025072.html#autoid-1-1-0 进程同步(multiprocess.Lock.Semaph ...

  4. python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))...

    昨日内容回顾 python中启动子进程 并发编程 并发 :多段程序看起来是同时运行的 ftp 网盘 不支持并发 socketserver 多进程 并发 异步 两个进程 分别做不同的事情 创建新进程 j ...

  5. 【C++】多线程互斥锁、条件变量

    我们了解互斥量和条件变量之前,我们先来看一下为什么要有互斥量和条件变量这两个东西,了解为什么有这两东西之后,理解起来后面的东西就简单很多了!!! 先来看下面这段简单的代码: int g_num = 0 ...

  6. day034 锁,信号量,事件,队列,子进程与子进程通信,生产者消费者模型,joinableQueue...

    进程锁 #加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全. 虽然可以用文件共享数据实现进程间通信,但问题是: 1 ...

  7. 【Linux】多线程--互斥锁

    文章目录 前言 基础概念 互斥量mutex 多线程模拟抢票(没加锁情况) 为何多线程访问临界资源是不安全 互斥锁相关接口 多线程模拟抢票(有加锁) 互斥锁实现的基本原理 前言 为什么线程需要同步和互斥 ...

  8. Windwos下的互斥锁,事件以及事件的手动重置和自动重置的区别

    事件的自动重置:两个线层同时访问一个函数,该函数会对全局变量进行操作,用事件进行互斥,假设这个事件初始化有信号   在经过WAITFORSIGALOBJECT()后事件就会变为没有信号,另外一个线程无 ...

  9. Python多线程--互斥锁、死锁

    1.互斥锁 为解决资源抢夺问题,使用mutex = Threading.Lock()创建锁,使用mutex.acquire()锁定,使用mutex.release()释放锁. 代码一: import ...

最新文章

  1. ModuleNotFoundError: No module named 'tools.nnwrap' pytorch 安装
  2. 【Manning新书】可解释人工智能: 构建可解释机器学习系统
  3. Jquery 获取对象的几种方式介绍
  4. 2021高考成绩微信查询方法6,2021年高考成绩查询时间、入口及方法
  5. suse linux 查看内存,Suse linux查询内存大小的指令是什么?
  6. 帮别人改的代码 我也不知道他爬的什么 记录下
  7. 一个表的信息插入到另一个表里面,如果遇到重复的就覆盖
  8. 陆正耀为瑞幸数据造假道歉:非常自责 会全力挽回损失
  9. 意见簿---在批评中成长
  10. jquery显示与隐藏效果
  11. 我没钱 如何推广自己的网站
  12. go语言中金币分配训练--pm
  13. 高质量编程之编译警告级别
  14. python音频频谱分析软件_SpectrumView(音频频谱分析软件)
  15. 服务器gpt分区不能安装系统,安装Win10原版系统提示“Windows无法安装到GPT分区形式磁盘”怎么办...
  16. 区块链与金融基础设施——兼论Facebook Libra
  17. 2020.4.15华为实习招聘笔试题第三题
  18. Continuous Passive Motion (CPM)持续性被动运动
  19. 如何备份管家婆软件数据?3种方法详解
  20. 李兴华-JAVA10 第1章: Java语言简介

热门文章

  1. 有分工、无合作的大企业病
  2. (GPS移植三部曲)Linux下移植GPS应用程序之常见问题的分析与解决方法之三
  3. 《天河传说》详细攻略1
  4. 5G的到来会兴起哪些行业
  5. Centos下使用yum安装Mysql8(Mysql5.7)以及常见的配置和使用
  6. 企业开发项目完整流程
  7. 达梦DM8数据库安装和创建实例
  8. 网站被挂黑链会引起哪些后果
  9. 2020湖湘杯 wp
  10. Unity UGUI学习笔记