Win32 中关于进程和线程的协调工作是由同步机制来完成的,同步机制相当于线程间的红绿灯。

一. 同步和异步

举个例子:

PostMessage(),是把消息放到对方的消息队列中,然后不管三七二十一,就回到原调用点继续执行,这就是异步。

SendMessage(),就像调用一般性函数,直到调用的函数结束,才会回到原点,这就是同步行为。

二. Critical Sections

如果一个线程已经进入某个临界区,则另一个线程就绝不能够进入同一个临界区。


//初始化一个临界区
VOID InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection // critical section
);

//消除一个临界区
VOID DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection // critical section
);

//进入临界区
VOID EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection // critical section
);

//离开临界区
VOID LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection // critical section
);

例如:
CRITICAL_SECTION gCriticalSection;

void Function()
{
InitializeCriticalSection(&gCriticalSection);

EnterCriticalSection(&gCriticalSection);

//Do something here

LeaveCriticalSection(&gCriticalSection);

DeleteCriticalSection(&gCriticalSection);
}

一旦线程进入一个临界区,则它就可以一再的重复进入该临界区,当然每个进入操作都必须对应离开操作。

也就是EnterCriticalSection( ),可以嵌套。

但是千万不要在临界区中调用 sleep(),或任何 Wait..() 函数。

临界区的缺点是:没有办法知道进入临界区中的那个线程是生是死。如果那个线程在进入临界区后当掉了,而且没有退出来,那么系统就没有办法消除掉此临界区。

三. Mutexes

Mutexes 用途和 Critical Section 非常类似,线程拥有 mutex 就好象线程进入 critical section 一样,但是它牺牲速度以增加弹性。

一旦没有任何线程拥有那个 mutex,这个 mutex 便处于激发状态

它与临界区的区别是:

1. Mutexes 操作要比 Critical Section 费时的多。

2. Mutexes 可以跨进程使用,Critical Section 则只能在同一进程中使用。

3. 等待一个 Mutex 时,你可以指定"结束等待"的时间长度,而 Critical Section 则不行。

HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性,默认为NULL
BOOL bInitialOwner, // initial owner
LPCTSTR lpName // mutex 的名称,是一个字符串
);
//返回值:如果成功返回 handle,否则返回 NULL

HANDLE OpenMutex(
DWORD dwDesiredAccess, // access
BOOL bInheritHandle, // inheritance option
LPCTSTR lpName // object name
);
//打开一个已经存在的 mutex

BOOL ReleaseMutex(
HANDLE hMutex // handle to mutex
);

//调用过程如下:
CreateMutex(); //创建
WaitForXXXObject(); //等待

ReleaseMutex(); //释放
CloseHandle(); //关闭

说明:

1. Mutex 的拥有权:

Mutex 的拥有权并非属于那个产生它的线程,而是那个最后对些 Mutex 进行 WaitXXX() 操作并且尚未进行 ReleaseMutex() 操作的线程。

2. Mutex 被舍弃:

如果线程在结束前没有调用 ReleaseMutex(),比如线程调用了 EXitThread() 或者因为当掉而结束。这时的 mutex 不会被摧毁,而是被视为"未被拥有"以及"未被激发"的状态,在下一个 WaitXXX() 中线程会被以WAIT_ABANDONED_0 (WAIT_ABANDONED_0_n + 1 )来通知。

3. 最初拥有者:

CreateMutex(),第二个参数 bInitialOwner,允许你指定现行线程是否立刻拥有产生出来的 mutex。

如果没有指定立刻拥有的情况:

HANDLE hMutex = CreateMutex(NULL, FALSE, "Sample Name");

int result = WaitForSingleObject(hMutex, INFINITE);

可能发生,在 CreateMutex 完成之后,发生了 context switch,执行权切换到另一个线程,那么其它进程就有可能在 mutex 的产生者调用 WaitForSingleObject( ) 之前,锁住这个 mutex 对象。