在进程内核对象的内部有一个布尔变量,当系统创建内核对象的时候会把这个变量的值初始化为FALSE(未触发)。当进程终止的时候,操作系统会自动把相应的内核对象中的这个布尔值设为TRUE,表示该对象已经被触发。
线程内核对象也遵循同样的规则,与进程内核对象相同,线程内核对象绝对不可能回到未触发状态。
Windows提供了专门用来帮助我们进行线程同步的内核对象:事件、可等待计时器、信号量以及互斥量。
DWORD dw = WaitForSingleObject(hProcess, 5000);
switch(dw)
{
case WAIT_OBJECT_0:
//...
break;
case WAIT_TIMEOUT:
//...
break;
case WAIT_FAILED:
//...
break;
}
有两种不同类型的事件对象:手动重置事件和自动重置事件。当一个手动重置事件被触发的时候,正在等待该事件的所有线程都将变成可调度状态。而当一个自动重置事件被触发的时候,只有一个正在等待该事件的线程会变成可调度状态。
事件最通常的用途是,让一个线程执行初始化工作,然后再触发另一个线程,让它执行剩余的工作。
HANDLE CreateEvent(
PSECURITY_ATTRIBUTES psa,
BOOL bManualReset,
BOOL bInitialState,
PCTSTR pszName);
当调用SetEvent的时候,我们把事件变成触发状态。
当调用ResetEvent的时候,我们把事件变成未触发状态。
Microsoft为自动重置事件定义了一个等待成功所引起的副作用:当线程成功等到自动重置事件对象的时候,对象会自动地重置为未触发状态。这也正是自动重置对象名字的由来。对自动重置对象来说,通常不需要调用ResetEvent,这是因为系统会自动将事件重置。相反,Microsoft并没有为手动重置对象定义一个等待成功所引起的副作用。
信号量内核对象用来对资源进行计数。与其他所有内核对象相同,它们也包含一个使用计数,但它们还包含另外两个32位值:一个最大资源计数和一个当前资源计数。最大资源计数表示信号量可以控制的最大资源数量,当前资源计数表示信号量当前可用资源的数量。
如果当前资源计数大于0,那么信号量处于触发状态,如果当前资源计数等于0,那么信号量处于未触发状态。
HANDLE CreateSemaphore(
PSECURITY_ATTRIBUTE psa,
LONG lInitialCount,
LONG lMaximumCount,
PCTSTR pszName);
BOOL ReleaseSemaphore(
HANDLE hSemaphore,
LONG lReleaseCount,
PLONG plPreviousCount);
互斥量内核对象用来确保一个线程独占对一个资源的访问。互斥量与关键段的行为完全相同。但是互斥量是内核对象,而关键段是用户模式下的同步对象。这意味着互斥量比关键段慢。但这同时意味着不同进程中的线程可以访问同一个互斥量,这还意味着线程可以在等待对资源的访问权时指定一个最长等待时间。
CreateMutex ReleaseMutex
创建窗口的线程和执行用户界面相关的任务的线程不应该使用WaitForMultipleObjects,而应该使用MsgWaitForMultipleObjectsEx.这是因为前者会妨碍线程对用户在用户界面上的操作进行响应.
异步设备I/O
异步设备I/O允许线程开始读取操作或写入操作,但不必等待读取操作或写入操作完成。例如:当系统在载入文件的时候,线程可以忙着执行其他任务--创建窗口,初始化数据结构,等等。当初始化完成之后,线程可以将自己挂起,等系统通知它文件已经载入完毕。
在进程内核对象的内部有一个布尔变量,当系统创建内核对象的时候会把这个变量的值初始化为FALSE