windows中的线程同步

1.用户模式和内核模式

windows操作系统的运行方式是“双模式操作”

  • 用户模式:运行应用程序的基本模式,禁止访问物理设备,限制访问内存区域
  • 内核模式:操作系统运行时的模式,不会限制访问内存区域和硬件设备

定义这2种模式问了提高安全性,线程这种伴随内核对象创建的资源创建过程的转换过程:

  • 用户模式–>内核模式–>用户模式
  • 从用户模式切换到内核模式为了创建资源,从内核模式再次切换到用户模式为了执行应用程序的剩余部分。缺点:频繁的模式切换回影响性能。
用户模式同步
  • 无需操作系统的帮助,有点:速度快,简单。缺点:功能局限性。
内核模式同步
  • 优点:功能多。可以指定超时,防止产生死锁。
基于critical_section同步
  • 基于critical_section的同步中将运用“critical_section”对象,但这并非内核对象。与其他同步对象,他是进入进入临界区的一把“钥匙”。因此,为了进入临界区,需要得到critical_section对象这把“钥匙”。相反,离开时,需要上交critical_section对象

2.内核模式的同步方法

基于事件(Event),信号量、互斥量

基于互斥量对象的同步

1.和上面cs类似,首先创建互斥量对象的函数

#include <windows.h>  
HANDLE CreateMutex(lpsecurity_attrubutes lpMutexAttributes, bool bInitialOwner, lpctstr lpName);
  • lpsecurity_attrubutes :传递安全相关配置信息,默认传递NULL
  • bInitialOwner:如果为TRUE,则创建出的互斥量对象属于调用该函数的线程,同时进入non-signaled状态;如果为false,则创建出的互斥量对象不属于任何线程,此时状态为signaled。
  • IpName:用于命名互斥量对象,传入NULL时创建无名的互斥量对象

如果互斥量对象不属于任何拥有着,进入signaled状态,利用该特点进行同步。
2.函数销毁,因为属于内核对象,所以销毁

#include <windows.h>
bool CloseHandle(handle hObject);
  • hObject:要销毁的内核对象的句柄
    3.获取和释放互斥量的函数
#include <windows.h>
bool ReleaseMutex(handle hMutex);
  • hMutex:需要释放(解除拥有)的互斥量对象句柄
    分析获取和释放互斥量的过程,互斥量被某一个线程获取时为non-signaled状态,释放时进入signaled状态。因此,可以使用WaitForSingleObject函数验证互斥量是否已分配,该函数调用结果2种:
  • 调用后进入阻塞状态:互斥量对象已被其他线程获取,现处于non-signaled状态
  • 调用后直接返回:其他线程未占用互斥量对象,现处于signaled状态。
    WaitForSingObject函数使互斥量进入non-signaled状态,限制访问临界区,所以相当于临界区的门禁系统。相反,ReleaseMutex函数使互斥量重新进入signal状态,相当于临界区的出口。
基于信号量对象的同步

与linux下的信号量类似,都是利用“信号量”的整数值完成同步,而且该值都不能小于0,windows信号量值注册于内核对象
1.创建信号量对象函数,销毁利用CloseHandle函数进行

#include <windows.h>
handle CreateSemaphore(lpsecurity lpSemaphoreAttributes, 
	long lInitialCount, long lMaximumCount, lpctstr lpName);
  • lpSemaphoreAttributes:安全配置信息,采用默认安全设置时传递NULL
  • lInitialCount:指定信号量的初始值,大于0小于lMaximumCount
  • lMaximumCount:信号量的最大值,该值为1时,信号量变为只能表示0和1二进制信号量
  • lpName:命名信号对象,传递NULL时创建无名的信号量对象

当lInitialCount参数传递0,创建non-signaled状态的信号量对象。lMaximumCount传入3时,信号量最大值为3,可以实现3个线程同时访问临界区时的同步。

2.释放信号量对象的函数

#include <windows.h>
bool ReleaseSemaphore(handle hSemaphore, 
		long lReleaseCount, lplong lpPreviousCount);
  • hSemaphore:传递需要释放的信号量对象
  • lReleaseCount:释放意味着信号量的增加,该参数可以指定增加的值,超多最大值则不增加,返回FALSE
  • lpPreviousCount:保存修改之前值的地址,不需要时传递NULL

信号量对象值大于0时成为signaled状态,为0成为non-signaled状态,因此调用WaitForSingleObject函数,信号量大于0情况下才会返回。返回时同时将信号量值减1,同时进入non-signaled状态(仅限信号量减1后等于0的情况)

waitForSingleObject(hSemaphore, infinite);
//临界区的开始
//。。。。。。uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
// 临界区的结束
ReleaseSemaphore(hSemaphore, 1, NULL);
基于事件对象的同步

与前2中同步方式相比很大不用,该方式创建对象时可以自动以non-signaled状态运行的auto-reset模式与相反的mamual-reset模式中任选其一。而事件对象主要的特点可以创建mamual-reset模式的对象
1.创建事件对象函数

#include <windows.h>
handle CreateEvent(lpsecurity_attributes lpEventAttributess, bool bManualRest,
		bool bInitialState, lpctstr lpname);
)
  • lpsecurity_attributes :安全配置参数,默认NULL
  • bManualRest:传入true时创建manual-reset模式的事件对象,传入FALSE时创建auto-reset模式事件对象
  • bInitialState:传入TRUE时创建signaled状态的事件对象,传入FALSE时创建non-signaled状态事件对象
  • lpname:用于命名时间对象,传递NULL时创建事件对象

重点是第二个参数,传入TRUE时创建manual-reset模式的事件对象,此时即使WaitForSingleObject函数返回也不会回到non-signaled状态,因此,需要通过2个函数明确更改对象状态

#include <windows.h>
bool ResetEvent(handle hEvent);
bool SetEvent(handle hEvent);

传递事件对象句柄希望改成non-signaled状态时,应调用ResetEvent函数,如果改为signaled状态,调用SetEvent函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值