内核态线程同步(2)利用内核对象同步

事件对象

event对象常用来多个线程间进行工作的同步,如线程A先执行一些初始化工作,触发evnet,通知线程B初始化工作已经完成,可以进行接下来的工作。

创建event对象HANDLE WINAPI CreateEvent( _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, // 设置安全属性 _In_BOOL bManualReset,// 是否人工重置状态(人工重置则不会自动改变事件状态, 自动重置则会自动将事件恢复为未触发) _In_BOOL bInitialState,// 事件初始状态(触发/未触发) _In_opt_ LPCTSTR lpName// 事件名称);值得注意的是<span style="color:#FF0000;">BOOL bManualReset, </span> 若 为人工重置,那么当事件触发时,所有等待线程均能够获得事件对象,且不会自动重置事件状态。若为自动重置,则仅有一个线程wait获得该事件,同时置事件为未触发状态。

另外一点,其他线程若想获得该事件对象句柄,可以也调用CreateEvent函数,并传入事件名称。若该事件已经存在,则直接返回句柄,若未存在则会创建该事件并返回句柄。

注意,若事件已经存在,再调用CreateEvent只会获取其句柄,但该函数的其他参数会忽略。

对于自动重置事件,若multiplewait函数为全部等待状态,则对于仅自动重置事件触发时,multiplewait函数会忽略该event,同时不会重置事件,只有当所有的等待对象都触发时,multiplewait才会获取自动重置事件并自动重置为未触发状态。

若想在创建事件时指定的可以访问事件的权限,,可以用

HANDLE WINAPI CreateEventEx( _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes, _In_opt_ LPCTSTR lpName, _In_DWORD dwFlags,// 可以是两种flags的任意组合<strong>CREATE_EVENT_INITIAL_SET</strong>、<strong>CREATE_EVENT_MANUAL_RESET</strong> _In_DWORD dwDesiredAccess// 设置事件权限);获取事件句柄函数HANDLE WINAPI OpenEvent( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ LPCTSTR lpName);改变事件触发状态设置事件为触发状态BOOL WINAPI SetEvent( _In_ HANDLE hEvent);设置事件未触发状态BOOL WINAPI ResetEvent( _In_ HANDLE hEvent);可等待计时器内核对象

可等待计时器对象会在一定时后或每间隔一段时间触发,可用在某个时间的操作。

创建或获取可等待计时器HANDLE WINAPI CreateWaitableTimer( _In_opt_ LPSECURITY_ATTRIBUTES lpTimerAttributes, _In_BOOL bManualReset,// 是否人工重置 _In_opt_ LPCTSTR lpTimerName);获取可等待计时器句柄HANDLE WINAPI OpenWaitableTimer( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ LPCTSTR lpTimerName);不像事件对象,可等待计时器创建后总是未触发的。

需要调用函数 SetWaitableTimer

BOOL WINAPI SetWaitableTimer( _In_HANDLE hTimer,// 计时等待对象 _In_const LARGE_INTEGER *pDueTime,// 何时触发对象(用负值表示相对于调用SetWaitableTimer后的时间 100纳秒为单位) _In_LONG lPeriod,// 触发后间隔的触发频率(0 表示仅触发一次) _In_opt_ PTIMERAPCROUTINE pfnCompletionRoutine, // APC调用函数 _In_opt_ LPVOID lpArgToCompletionRoutine,// APC调用参数 _In_BOOL fResume// 在可挂起的计算机系统中,是否恢复计算机来使等待线程执行CPU时间。// 若传入FALSE,则会触发对象,但等待线程不会执行,除非直到计算机系统重新执行 );取消计时等待对象的时间设置该函数会取消一切的SetWaitableTimer的计时设置。<strong>但是该函数不会更改timer对象的触发状态</strong>,若已经触发,则该对象仍会处于触发状态。BOOL WINAPI CancelWaitableTimer( _In_ HANDLE hTimer);计时等待对象 VS 用户计时器(SetTimer)

1、内核对象,用户对象

2、用户计时器会产生WM_TIMER消息,该消息会被送到调用SetTimer线程或创建窗口线程,同一时间仅有一个线程得到通知。

计时等待对象可多个线程同时被通知。

信号量内核对象

信号能够灵活的限制可被激活的线程数目,并确保线程数目不会超过设定的最大值。

具体使用流程为:

1、创建信号量对象,并指定最大资源数目与当前可用数目(常为0)。

2、创建多个资源请求线程,因为当前可用数目为0,线程等待。

3、当符合某种条件时,调用ReleaseSemaphore函数释放资源,这时候可用资源数目递增。

4、可以资源数目不再为0,等待线程获得资源,同时可以资源数目递减。

windows系统会确保当前可用资源数目大于等于0,同时不会超过最大值。

创建(或获取)信号量对象HANDLE WINAPI CreateSemaphore( _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, _In_LONG lInitialCount,// 初始当前可用资源数目 _In_LONG lMaximumCount,// 最大可用资源数目 _In_opt_ LPCTSTR lpName);CreateSemaphoreEx

获取信号量对象句柄HANDLE WINAPI OpenSemaphore( _In_ DWORD dwDesiredAccess, _In_ BOOL bInheritHandle, _In_ LPCTSTR lpName);递增信号量可用资源BOOL WINAPI ReleaseSemaphore( _In_HANDLE hSemaphore, _In_LONG lReleaseCount, _Out_opt_ LPLONG lpPreviousCount);互斥量内核对象

互斥量内核对象用于确保资源被唯一的线程访问,即互斥访问。

创建(获取)互斥量对象HANDLE WINAPI CreateMutex( _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, _In_BOOL bInitialOwner, _In_opt_ LPCTSTR lpName);

互斥量内核对象 有 引用计数器,线程ID已经递归计数器组成。

线程ID用来记录当前获取互斥量对象的线程ID,0表示没人获取,互斥量处于触发状态。一旦,有个线程wait到互斥量,其内核对象线程ID为该线程ID,同时内核对象变为未触发状态,其他线程只能继续等待。但对于已经获得互斥量线程,其仍可以等待成功,这时候内核对象会递增其递归计数器。

调用ReleaseMutex 释放互斥量。对于多次递归进入的互斥量,要相应的多次调用release函数。

注意,当线程在获取了互斥量对象,而在调用ReleaseMutex之前结束的话,会产生遗弃问题。

关于内核态同步对象的一些事项梦想,并不奢侈,只要勇敢地迈出第一步。

内核态线程同步(2)利用内核对象同步

相关文章:

你感兴趣的文章:

标签云: