线程初始化、申请、进入、释放临界区
InitializeCriticalSection
初始化临界区对象,出参为指向临界区对象的指针。
void InitializeCriticalSection(
[out] LPCRITICAL_SECTION lpCriticalSection
);
说明
- 单个进程的线程可以使用临界区对象进行互斥同步。不能保证线程获得临界区所有权的顺序,但是,系统对所有线程都是公平的。
- 进程负责分配临界区对象使用的内存,可以通过声明一个CRITICAL_SECTION类型的变量来实现。在使用临界区之前,进程的某个线程必须初始化该对象。
- 初始化临界区对象后,进程的线程可以在EnterCriticalSection、TryEnterCriticalSection或leaveccriticalsection函数中指定该对象,以提供对共享资源的互斥访问。对于不同进程的线程之间的类似同步,使用互斥对象。
- 临界区对象不能移动或复制。进程也不能修改对象,但必须将其视为逻辑上不透明的。只使用临界区函数来管理临界区对象。使用完临界区后,调用DeleteCriticalSection函数。
- 临界区对象必须在重新初始化之前被删除。初始化已经初始化的临界区会导致未定义的行为。
DeleteCriticalSection
释放无主临界区对象使用的所有资源。
void DeleteCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
说明
- 删除临界区对象将释放该对象所使用的所有系统资源。调用者需要确保临界区对象已被释放,并且不会被进程中其他线程的临界区函数访问。
- 删除临界区对象后,除了initializeccriticalsection和initializeccriticalsectionandspincount之外,不要在任何操作临界区(如EnterCriticalSection、TryEnterCriticalSection和leaveccriticalsection)的函数中引用该对象。否则可能会发生内存损坏和其他意想不到的错误。
- 如果一个临界区删除前未释放,那么等待该临界区所有权的线程状态是未定义的。
EnterCriticalSection
等待指定临界区对象的所有权。当调用线程被授予所有权时,函数返回。
void EnterCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
说明
- 单个进程的线程可以使用临界区对象进行互斥同步。进程负责分配临界区对象使用的内存,可以通过声明一个CRITICAL_SECTION类型的变量来实现。在使用临界区之前,进程的某些线程必须调用initializeccriticalsection或initializeccriticalsectionandspincount来初始化对象。
- 为了实现对共享资源的互斥访问,每个线程在执行访问受保护资源的任何代码段之前,调用EnterCriticalSection或TryEnterCriticalSection函数来请求临界区的所有权。不同之处在于,TryEnterCriticalSection立即返回,而不管它是否获得了临界区的所有权,而EnterCriticalSection阻塞直到线程可以获得临界区的所有权。当线程完成执行受保护的代码时,它使用leaveccriticalsection函数放弃所有权,使另一个线程成为所有者并访问受保护的资源。不能保证等待线程获得临界区所有权的顺序。
- 在线程拥有临界区所有权之后,它可以在不阻塞其执行的情况下对EnterCriticalSection或TryEnterCriticalSection进行额外调用。这可以防止线程在等待它已经拥有的临界区时发生死锁。每次EnterCriticalSection和TryEnterCriticalSection成功时,线程进入临界区。线程必须在每次进入临界区时调用一次leaveccriticalsection。
- 进程的任何线程都可以使用DeleteCriticalSection函数来释放初始化临界区对象时分配的系统资源。调用此函数后,临界区对象不能再用于同步。
- 如果线程在拥有临界区时终止,则该临界区的状态未定义。
- 如果一个临界区被删除,而它仍然是所有者,那么等待被删除的临界区所有权的线程的状态是未定义的。
- 当进程退出时,如果调用EnterCriticalSection会阻塞,它将立即终止进程。这可能导致不调用全局析构函数。
LeaveCriticalSection
释放指定临界区对象的所有权。
void LeaveCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
说明
- 单个进程的线程可以使用临界区对象进行互斥同步。进程负责分配临界区对象使用的内存,这可以通过声明一个CRITICAL_SECTION类型的变量来实现。在使用临界区之前,进程的某些线程必须调用initializeccriticalsection或initializeccriticalsectionandspincount函数来初始化对象。
- 线程使用EnterCriticalSection或TryEnterCriticalSection函数来获取临界区对象的所有权。为了释放它的所有权,线程必须在每次进入临界区时调用一次leaveccriticalsection。
- 如果一个线程在没有指定临界区对象的所有权时调用leaveccriticalsection,则会发生一个错误,可能导致使用EnterCriticalSection的另一个线程无限期地等待。
- 在释放临界区对象的所有权之后,leaveccriticalsection不会访问指定的CRITICAL_SECTION结构。
- 进程的任何线程都可以使用DeleteCriticalSection函数来释放初始化临界区对象时分配的系统资源。调用此函数后,临界区对象不能再用于同步。
使用示例
#include "synchapi.h"
#include "afxmt.h"
CRITICAL_SECTION CriticalSection;
int main( void )
{
...
// 只初始化一次临界区。
if (!InitializeCriticalSectionAndSpinCount(&CriticalSection,
0x00000400) )
return;
...
// 释放临界区对象使用的资源。
DeleteCriticalSection(&CriticalSection);
}
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{
...
// 请求临界区的所有权。
EnterCriticalSection(&CriticalSection);
// 访问共享资源。
// 释放临界区的所有权。
LeaveCriticalSection(&CriticalSection);
...
return 1;
}