• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

技术天地

windows多线程关键段 CriticalSection

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/2019/0713/575.html

 
一、问题回想
我们常州微信公众平台上一篇文章最后的程序的输出 g_Count 的值不是每次都正确,缘由是没有对全局资源 g_Count 中止互斥访问(就是同一时辰只能由一个线程访问),接下来我们就来说一下运用关键段来给全局资源加锁以完成互斥访问。
 
这是上一篇中的程序:
 
 
#include <stdio.h>
#include <windows.h>
 
const unsigned int THREAD_NUM = 50;
unsigned int g_Count = 0;
DWORD WINAPI  ThreadFunc(LPVOID);
 
 
int main()
{
    HANDLE hThread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++)
    {
        hThread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
    }
    WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE);    //不时等候,直到一切子线程全部返回
    printf(" 总共 %d 个线程给 g_Count 的值加一,往常 g_Count = %d\n", THREAD_NUM, g_Count);
    return 0;
}
 
DWORD WINAPI  ThreadFunc(LPVOID p)
{
    Sleep(50);
    g_Count++;
    Sleep(50);
    return 0;
}
二、 关键段 CriticalSection 声明及相关函数
(一)CriticalSection 声明
CRITICAL_SECTION 关键段名字;  // eg: CRITICAL_SECTION cs;
CRITICAL_SECTION 结构说明:在 vs 中 先声明一个 关键段, 鼠标放到 CRITICAL_SECTION 关键字上按 F12 转到定义如下:
 
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
再把鼠标放到 RTL_CRITICAL_SECTION 上按 F12 即可转到常州微信小程序开发CRITICAL_SECTION 结构体的定义 如下:
 
 
 
 
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;
第一个参数:PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 调试的时分用的,先不做引见。
 
第二个参数:LONG LockCount; 初始化为-1,n表示有n个线程在等候。
 
第三个参数:LONG RecursionCount; 表示该关键段的具有线程对此资源获得关键段次数,初为0。
 
第四个参数:HANDLE OwningThread; 即具有该关键段的线程句柄
 
第五个参数:HANDLE LockSemaphore; 理论上是一个自复位事情。
 
第六个参数:ULONG_PTR SpinCount; 旋转锁的设置,用于多处置器。
 
(二)CriticalSection相关函数
1.函数功用:初始化,定义关键段变量后必需先初始化。
 
void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
2.函数功用:销毁,用完之后记得销毁。
 
void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
3.函数功用:进入关键区域,系统保证各线程互斥的进入关键区域。
 
void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
4.函数功用:分开关关键区域
 
void LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
三、常州网站开发建设实例
往常运用关键段来处置上面的问题,代码如下:
 
 
#include <stdio.h>
#include <windows.h>
 
const unsigned int THREAD_NUM = 50;
unsigned int g_Count = 0;
CRITICAL_SECTION cs; //声明关键段
DWORD WINAPI  ThreadFunc(LPVOID);
 
int main()
{
    InitializeCriticalSection(&cs); // 初始化关键段
    HANDLE hThread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++)
    {
        hThread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
    }
    WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE);    //不时等候,直到一切子线程全部返回
    printf(" 总共 %d 个线程给 g_Count 的值加一,往常 g_Count = %d\n", THREAD_NUM, g_Count);
    DeleteCriticalSection(&cs);     //销毁关键段
    return 0;
}
 
DWORD WINAPI  ThreadFunc(LPVOID p)
{
    Sleep(50);
    EnterCriticalSection(&cs);  // 进入关键段
    g_Count++;
    LeaveCriticalSection(&cs);  // 分开关键段
    Sleep(50);
 
    return 0;
}
游戏开发运营结果如下图所示,给全局资源 g_Count 加锁,完成互斥访问,就能够让每个线程正确给 g_Count 值加一 :
 

上篇:上一篇:c++使用curl库访问服务器并获取应答结果
下篇:下一篇:Microsoft Visual C++ 2008 发布程序的部署问题