C++拾遗--多线程:临界区解决子线程的互斥

来源:互联网 发布:手机视频软件免费 编辑:程序博客网 时间:2024/04/30 04:52

                  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 50CRITICAL_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");//初始化关键段变量csInitializeCriticalSection(&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;}//销毁关键段变量csDeleteCriticalSection(&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;


关键段就是一结构体。具体原因后续分析……





本专栏目录

  • C++拾遗 目录
所有内容的目录
  • CCPP Blog 目录

1 0