第九章:用内核对象进行线程同步(二) .
来源:互联网 发布:下载解压软件 编辑:程序博客网 时间:2024/05/30 04:29
7 互斥量内核对象用来确保一个线程独占对一个资源的访问.
■ 组成:
①使用计数
②线程ID:标示当前占用这个互斥量的是系统中那个线程
③递归计数: 表示这个线程占用该互斥量的次数.
■ 与关键代码段的区别:
● 互斥量是内核模式下的,而关键代码段是用户模式下的.也意味着关键代码段比 互斥量要快.
● 不同进程中的线程可以访问同一个互斥量.
■ 互斥量的规则:
● 如果线程ID为0(即无效线程ID),那么该互斥量不为任何线程锁占有,它处于触 发状态
● 如果线程ID为非0,那么有一个线程已经占用了该互斥量,它处于未触发状态
● 与所有其他内核对象不同,OS对互斥量进行了特殊处理,欲行它们违反一些常 规的规则.
■ 互斥量的一些操作
● 创建
HANDLE CreateMutex(
PSECUTRY_ATTRIBUTES psa,
BOOL bInitialOwner,//互斥量的初始状态(TRUE表示处于未触发状态)线程ID //和递归计数分别设为当前线程ID和1
PCTSTR pszName);
HANDLE CreateMutexEx(
PSECUTRY_ATTRIBUTES psa,
PCTSTR pszName,
DWORD dwFlags,//相当于bInitialOwner(0表示 //FALSE,CREATE_MUTEX_INITIAL_OWNER等价于TRUE
DWORD dwDesiredAccess);
● 获取互斥量句柄
HANDLE OpenMutex(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
PCTSTR pszName);
● 释放互斥量,使其处理可触发状态.
BOOL ReleaseMutex(HANDLE hMutex);
函数工作方式:使得对象的递归计数减一.如果线程成功地等待了互斥量对象不止一次,那么线程必须调用相同次数ReleaseMutex使得递归计数为0,并且此时线程ID也设为0.这样就出发了对象.
互斥量与其他内核对象的区别:
加入线程试图等待一个未触发的互斥量对象,线程就会进入等待状态,但是如果系统检查想要获得互斥量的线程的ID与互斥量对象内部记录的线程ID相等那么此时系统也会让线程保持可调度状态--即使该互斥量尚未触发.
■ 互斥量与其它内核对象不同的根本原因是"所有权"问题:也就是说,其它内核对象不会记住自己是哪个线程等待成功的.这就使得他即使在未触发状态下也能为线程所得.
这样就会出现一种情况是,如果占用互斥量的线程在释放互斥量之前终止,那么互斥量将出现"遗弃".
由于系统记录着所有的互斥量和线程内核对象,所以他有能力使得被遗弃的互斥量重新变为触发状态.这样其他的等待互斥量的线程就可以获取到互斥量的资源.但是这里有一个小小的不同:处于等待的函数不在返回通常的WAIT_OBJECT_0而是返回WAIT_ABANDONED.
■ 互斥量和关键段的区别:
特征
互斥量
关键段
是否能跨进程使用
慢
快
声明
HANDLE hmtx
CRITICAL_SECTION cs
初始化
Hmtex = CreateMutex(NULL,FALSE,NULL)
InitializeCriticalSection(&cs)
清理
CloseHandle(hmtx)
DeleteCriticalSection(&cs)
无限等待
WaitForSignalObject(hmtx,INFINITE)
EnterCriticalSection(&cs)
0等待
WaitForSignalObject(hmtx,INFINITE)
TryEnterCriticalSection(&cs)
任意时间长度等待
WaitForSingleObject(hmtx,dwMilliseconds)
不支持
释放
ReleaseMutex(hmtx)
LeaveCriticalSection(&cs)
能否同时等待其他内核对象
是(使用WaitForMultipleObject或者类似的函数)
否
线程同步对象速查表:
对象
何时处于未触发状态
何时处于触发状态
成功等待的副作用
进程
进程仍在运行
进程终止时(ExitProcess或者TerminateProcess)
没有
线程
线程仍在运行时
线程终止的时候(Exit(Terminate)Thread
没有
作业
作业尚未超时时
作业超时时
没有
文件
有待处理的I/O请求的时
I/O请求完成时
没有
控制台输入
没有输入时
有输入时
没有
文件变更通知
文件没有变更通知时
文件系统检测到变更时
重置通知
自动重置事件
ResetEvent,PulseEvent或等待成功时
SetEvent/PulseEvent被调用时
重置事件
手动重置事件
ResetEvent,PulseEvent
SetEvent/PulseEvent被调用时
没有
自动重置可等待计时器
CancelWaitableTimer或者等待成功的时候
时间到时(SetWaitableTimer)
重置计数器
手动重置可等待计时器
CancelWaitableTimer
时间到时(SetWaitableTimer)
没有
信号量
等待成功时
计数大于0(ReleaseSemaphore)
计数器减一
互斥量
等待成功的时候
不为线程占用时(ReleaseMutex)
把所有权交给线程
关键段(用户模式)
等待成功时((Try)EnterCriticalSection)
不为线程占用时(LeaveCriticalSection)
把所有权交给线程
SRWLock(用户模式)
等待成功时(AcquireSRWLock(Exclusive))
不为线程占用时(ReleaseSRWLock(Exclusive))
把所有权交给线程
条件变量(用户模式)
等待成功时(SleepConditionVariable*)
被唤醒时(Wake(All)ConditionVariable)
没有
Interlocked系列函数(用户模式)从来不会使得线程变为不可调度状态,它们只是修改一个值,并立即返回.
8 异步设备I/O:允许线程开始读取操作或者写操作,而不需等待读取操作或者等待操作完成.设备对象时可同步的内核对象,即我们可以调用WaitForSignalObject,并传入文件句柄、套接字、通信端口等等。当系统执行异步的I/O的时候,设备处于为触发状态,一旦操作完成,系统将变成触发状态。这样线程就知道操作已经完成了,线程就可以继续执行。
函数:DWORD WaitForInputIdle(
HANDLE hProcess,
DWORD dwMillseconds);
先挂起当前进程,然后等待hProcess标示的进程,直到创建应用程序第一个窗口的(也就是hProcess标示的进程)线程中没有待处理的输入为止.
线程也可以调用MsgWaitForMultipleObjects或MsgWaitForMultipleObjsEx,使得线程等待需要自己处理的消息.
DWORD MsgWaitForMultipleObjects(
DWORD dwCount,
PHANDLE phObjects,
BOOL bWaitAll,
DWORD dwMilliseconds,
DWORD dwWakeMask);
DWORD MsgWaitForMultipleObjectsEx(
DWORD dwCount,
PHANDLE phObjects,
DWORD dwMilliseconds,
DWORD dwWakeMask,//标示是哪类消息.
DWORD dwFlags);
这些函数与WaitForMultipleObjects类似,不同之处在于,不仅内核对象被触发的时候调用线程会变成可调度状态,而且当窗口消息需要被派送到一个由调用线程创建的窗口时,他们也会变成可调度状态.
创建窗口的线程和执行与用户界面相关的任务线程都不应该使用WaitForMultipleObjects,而应该使用MsgWaitForMultipleObjectsEx.因为前者会妨碍线程对用户在用户界面上的操作进行响应.
9. 当调试器开始执行的时候,会将自己附着到被调试的程序.然后调试器只是在一边闲着,等待操作系统通知它有与被调试程序相关的时间发生.调试器通过WaitForDebugEvent函数类等待这些时间:
BOOL WaitForDebugEvent(
PDEBUG_EVENT pde,
DWORD dwMillsecond);
当调试器调用这个函数的时候,调试器的线程会挂起,系统通过让WaitForDebugEvent返回的方式,来通知调试器有调试事情发生.参数pde指向的结构包含了与刚才发生的调试事件有关的信息.
10. SignalObjectAndWait函数通过一个原子操作来触发内核对象并等待另一个内核对象:
DWORD SignalObjectAndWait(
HANDLE hObjectToSignal,//标示的必须是一个互斥量、信号量或者事件.
HANDLE hObjectToWaitOn,//标示互斥量、信号量、事件、计时器、进程、线程、 //作业、控制台输入以及变更通知.
DWORD dwMilliseconds,//最多应该花多长时间来等待对象触发
BOOL bAlertable); //当线程处于等待状态时,是否能够对添加到队列中的异步 //过程调用进行处理
hObjectToSignal:任何其它类型对象将导致函数返回WAIT_FAILED.这时使用GetLastError会返回ERROR_INVALID_HANDLE.该函数内部会检查对象的类型并分别执行与ReleaseMutex、ReleaseSemaphore(使用计数减一)或者SetEvent等价的操作.
返回值:WAIT_OBJECT_0,WAIT_OBJECT_TIMEOUT,WAIT_FAILED,WAIT_ABANDONED或者WAIT_IO_COMPLETION.
函数的优点:花费时间短.
10. Vista提供了一组新的等待链遍历(简称WCT)API,这些函数可以让我们列出所有锁,并检测进程内部,甚至是进程之间的死锁.
可能的锁
描述
关键段
Windows会记录哪个线程正在占用哪个关键段
互斥量
Windows户记录哪个线程正在占用哪个互斥量,即使被遗弃
进程和线程
Window会记录哪个线程正在等待进程终止或者线程终止
SendMessage调用
知道那个线程正在等待SendMessage调用返回时很重要的
COM初始化和调用
Windows会记录对CoCreateInstance的调用以及对COM对象的方法的调用
高级本地过程调用
在windows Vista中,作为新的未公开的内核进程间通信机制,ALPC已经取代了本地过程调用.
剩下一点,运行xp无法调试起来,很悲剧.明天再看- 第九章:用内核对象进行线程同步(二) .
- 第九章:用内核对象进行线程同步
- 第九章:用内核对象进行线程同步(一)
- 第九章 使用内核对象进行线程同步
- <<Windows核心编程(第五版)>>第九章用内核对象进行线程同步:9.3事件内核对象
- 用内核对象进行线程同步1
- windows 用内核对象进行线程同步
- 用内核对象进行线程同步
- 用内核对象进行线程同步
- Windows核心编程:用内核对象进行线程同步
- Windows核心编程 用内核对象进行线程同步
- windows核心编程-9.用内核对象进行线程同步
- windows核心编程-用内核对象进行线程同步
- windows核心编程---用内核对象进行线程同步
- 用内核对象同步线程
- 《Windows核心编程》第9章 用内核对象进行线程同步
- 《Windows核心编程 5th》读书笔记----第9章 用内核对象进行线程同步
- Windows核心编程 第九章 线程与内核对象的同步(上)
- oracle 跟踪文件和转储命令详解
- linux 多线程编程的信号问题
- SDL使用触屏模拟鼠标点击事件
- Java中string的特性
- 每日一句(想起来的时候~哈)
- 第九章:用内核对象进行线程同步(二) .
- 数据库的工具类!
- IOS 入门开发之创建标题栏UINavigationBar的使用(二)
- android中的广播
- String.getBytes()方法中的中文编码问题
- Ubuntu 10.04更新源大全
- Linux C中read/write,fread/fwrite等的使用说明!
- js操作select控件
- Shutdown 详解