C++拾遗--多线程:临界区解决子线程的互斥
C++拾遗--多线程:临界区解决子线程的互斥
前言
为了解决子线程的互斥问题,windows系统提出了关键段或临界区(CRITICAL_SECTION)的概念。它一共有四个共两对操作:初始化、销毁,进入、离开。它们定义在头文件synchapi.h中。
1.初始化变量
VOID WINAPI InitializeCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
2.销毁变量
VOID WINAPI DeleteCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
3.进入临界区域
VOID WINAPI EnterCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
函数说明:系统保证各个子线程互斥的进入临界区域
4.离开临界区域
VOID WINAPI LeaveCriticalSection(
LPCRITICAL_SECTION lpCriticalSection
);
四个函数的使用都相当简单,传入CRITICAL_SECTION类型的变量地址即可。
正文
程序示例
下面我们使用关键段来解决子线程的互斥问题,程序代码类似于原子操作解决线程冲突。每一个子线程都对同一个全局变量累加10。这次我们开启50个子线程,查看最后的累加结果。
#include <stdio.h> #include <stdlib.h> #include <process.h> #include <Windows.h> #define Thread_NUM 50 CRITICAL_SECTION cs; int g_count = 0; void count(void *p) { Sleep(100); //do some work //每个线程把g_count加1共10次 for (int i = 0; i < 10; i++) { //进入临界区域 EnterCriticalSection(&cs); g_count++; //离开临界区域 LeaveCriticalSection(&cs); } Sleep(100); //do some work } int main(void) { printf("******临界区解决子线程冲突演示***by David***\n"); //初始化关键段变量cs InitializeCriticalSection(&cs); //共创建Thread_NUM个线程 HANDLE handles[Thread_NUM]; //共验证10次 for (int i = 0; i < 10; i++) { for (int j = 0; j < Thread_NUM; j++) { handles[j] = _beginthread(count, 0, NULL); } WaitForMultipleObjects(Thread_NUM, handles, 1, INFINITE); printf("%d time g_count = %d\n", i, g_count); //重置 g_count = 0; } //销毁关键段变量cs DeleteCriticalSection(&cs); getchar(); return 0; }运行
从运行结果看,使用关键段确实可以解决子线程的冲突问题。在g_count++;的前后我们加上关键段的进入和离开,使这句代码成为了“临界”区域。至此,g_count++;的操作就十分类似于原子操作。下面我们来详细分析下关键段的使用原理。
关键段原理
关键段的定义
在minwinbase.h中
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
而在winnt.h中
typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
//
// The following three fields control entering and exiting the critical
// section for the resource
//
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread; // from the thread‘s ClientId->UniqueThread
HANDLE LockSemaphore;
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
关键段就是一结构体。具体原因后续分析……
本专栏目录
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。