线程同步的方式主要有:临界区、互斥区、事件、信号量四种方式。
接下来我主要讲一下自己在学习windows核心编程中对于临界区线程同步方式的使用。
临界区线程同步在windows核心编程中被称为关键段线程同步,以下统称关键段
关键段是一小段代码,它在执行之前需要独占对一些资源的访问权。
缺点:能且只能用在一个进程中的多线程同步。可能陷入死锁,因为我们无法为进入关键段的线程设置最大等待时间。
接下来我介绍一些关键段线程同步的使用
先看一个事例代码
int g_nSum = 0; CRITICAL_SECTION g_cs; DWORD WINAPI FirstThread(PVOID pvParam) { EnterCriticalSection(&g_cs); g_nSum = 0; for (int n = 0; n < 10000; ++n) { g_nSum += n; } LeaveCriticalSection(&g_cs); return g_nSum; } DWORD WINAPI SecondThread(PVOID pvParam) { EnterCriticalSection(&g_cs); g_nSum = 0; for (int n = 0; n < 10000; ++n) { g_nSum += n; } LeaveCriticalSection(&g_cs); return g_nSum; }在使用关键段(CRITICAL_SECTION)时,只有两个必要条件:
//1、首先我们要分配一个CRITICAL_SECTION对象,并进行初始化(使用关键段同步的线程必须调用此函数) void InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) //2、当知道线程将不再需要访问共享资源时,我们应该调用下边的函数来清理CRITICAL_SECTION结构 void DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) //3、在对保护的资源进行访问之前,必须调用下面的函数 void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) //可以对上边的函数多次调用,表示调用线程被获准访问的次数 //4、也可以用下边的函数代替EnterCriticalSection BOOL TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) //通过返回值判断当前线程是否获准访问资源,线程永远不会进入等待状态,如果 //返回TRUE表示该线程获准并正在访问资源,离开时必须调用LeaveCriticalSection() //5、在代码完成对资源的访问后,必须调用以下函数,释放访问权限 void LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection ) //转载请注明文章来自:http://blog.csdn.net/windows_nt以上访问方式(EnterCriticalSection方式)可能会使调用线程切换到等待状态,这意味着线程必须从用户模式切换到内核模式,这个切换开销非常大。为了提高关键段的性能,Microsoft把旋转锁合并到了关键段中。因此,当调用EnterCriticalSection的时候,它会用一个旋转锁不断地循环,尝试在一段时间内获得对资源的访问权,只有当尝试失败时,线程才会切换到内核模式并进入等待状态。
//1、为了在使用关键段的时候同时使用旋转锁,我们必须调用下面的函数来初始化关键段 BOOL InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ) //第二个参数dwSpinCount表示我们希望旋转锁循环的次数。 //2、我们也可以调用下面的函数来改变关键段的旋转次数 DWORD SetCriticalSectionSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount ) //如果主机只有一个处理器,函数会忽略dwSpinCount参数
//1、首先我们要分配一个SRWLOCK对象并用下边函数初始化它。 void InitializeSRWLock( __out PSRWLOCK SRWLock ) //2、请求对保护资源的独占访问权(写权限) void AcquireSRWLockExclusive( __inout PSRWLOCK SRWLock ) //3、完成对资源的更新后,应该解除对资源的锁定 void ReleaseSRWLockExclusive( __inout PSRWLOCK SRWLock ) //4、对应的读者线程函数如下 void AcquireSRWLockShared( __inout PSRWLOCK SRWLock ) void ReleaseSRWLockShared( __inout PSRWLOCK SRWLock )与关键段相比,PSRWLOCK缺乏下面两个特性