1. 程式人生 > >window下執行緒同步之(Critical Sections(關鍵程式碼段、關鍵區域、臨界區域)----轉載

window下執行緒同步之(Critical Sections(關鍵程式碼段、關鍵區域、臨界區域)----轉載

轉載:https://www.cnblogs.com/cyblogs/p/9948379.html

 

 關鍵區域(CriticalSection)

臨界區是為了確保同一個程式碼片段在同一時間只能被一個執行緒訪問,與原子鎖不同的是臨界區是多條指令的鎖定,而原子鎖僅僅對單條操作指令有效;臨界區和原子鎖只能控制同一個程序中執行緒的同步

使用方法:

1、初始化:InitializeCriticalSection; 
2、刪除:DeleteCriticalSection; 
3、進入:EnterCriticalSection(可能造成阻塞); 
4、嘗試進入:TryEnterCriticalSection(不會造成阻塞); 
5、離開:LeaveCriticalSection;

固有特點(優點+缺點): 
1、是一個使用者模式的物件,不是系統核心物件; 
2、因為不是核心物件,所以執行速度快,有效率; 
3、因為不是核心物件,所以不能跨程序使用; 
4、可以多次“進入”,但必須多次“退出”; 
5、最好不要同時進入或等待多個 Critical Sections,容易造成死鎖; 
6、無法檢測到進入到 Critical Sections 裡面的執行緒當前是否已經退出!

 

一般錯誤的情況:

複製程式碼
#include <stdio.h> 
#include <windows.h>

long g_nNum = 0 ; 
DWORD WINAPI ThreadProc(__in  LPVOID lpParameter); 
const int THREAD_NUM = 10;

int main() 
{

    HANDLE  handle[THREAD_NUM];    
    g_nNum = 0; 
    int var = 0; 
    while ( var< THREAD_NUM) 
    { 
        handle[ var++] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

    } 
    WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

    for( var=0; var<sizeof(handle); var++) 
    { 
        CloseHandle(handle[var]); 
    }

    return 0; 
}

DWORD WINAPI ThreadProc(__in  LPVOID lpParameter) 
{ 
    Sleep(50); 
    g_nNum++; 
    Sleep(0); 
    printf("當前計數為:%d\n",g_nNum); 
    return 0; 
}
複製程式碼

執行2次結果:

image

image

用了關鍵區域的情況:

複製程式碼
#include <stdio.h> 
#include <windows.h>

long g_nNum = 0 ; 
DWORD WINAPI ThreadProc(__in  LPVOID lpParameter); 
const int THREAD_NUM = 10;

CRITICAL_SECTION g_ThreadCode;

int main() 
{

    HANDLE  handle[THREAD_NUM];    
    g_nNum = 0; 
    int var = 0; 
    InitializeCriticalSection(&g_ThreadCode); 
    while ( var< THREAD_NUM) 
    { 
        handle[ var++] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); 
    } 
    WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); 
    DeleteCriticalSection( &g_ThreadCode ); 
    
    for( var=0; var<sizeof(handle); var++) 
    { 
        CloseHandle(handle[var]); 
    }

    return 0; 
}

DWORD WINAPI ThreadProc(__in  LPVOID lpParameter) 
{  
    EnterCriticalSection( &g_ThreadCode ); 
    g_nNum++;  
    printf("當前計數為:%d\n",g_nNum); 
    LeaveCriticalSection( &g_ThreadCode ); 
    return 0; 
}
複製程式碼

 關鍵區域(CriticalSection)

臨界區是為了確保同一個程式碼片段在同一時間只能被一個執行緒訪問,與原子鎖不同的是臨界區是多條指令的鎖定,而原子鎖僅僅對單條操作指令有效;臨界區和原子鎖只能控制同一個程序中執行緒的同步

使用方法:

1、初始化:InitializeCriticalSection; 
2、刪除:DeleteCriticalSection; 
3、進入:EnterCriticalSection(可能造成阻塞); 
4、嘗試進入:TryEnterCriticalSection(不會造成阻塞); 
5、離開:LeaveCriticalSection;

固有特點(優點+缺點): 
1、是一個使用者模式的物件,不是系統核心物件; 
2、因為不是核心物件,所以執行速度快,有效率; 
3、因為不是核心物件,所以不能跨程序使用; 
4、可以多次“進入”,但必須多次“退出”; 
5、最好不要同時進入或等待多個 Critical Sections,容易造成死鎖; 
6、無法檢測到進入到 Critical Sections 裡面的執行緒當前是否已經退出!

 

一般錯誤的情況:

複製程式碼
#include <stdio.h> 
#include <windows.h>

long g_nNum = 0 ; 
DWORD WINAPI ThreadProc(__in  LPVOID lpParameter); 
const int THREAD_NUM = 10;

int main() 
{

    HANDLE  handle[THREAD_NUM];    
    g_nNum = 0; 
    int var = 0; 
    while ( var< THREAD_NUM) 
    { 
        handle[ var++] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);

    } 
    WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

    for( var=0; var<sizeof(handle); var++) 
    { 
        CloseHandle(handle[var]); 
    }

    return 0; 
}

DWORD WINAPI ThreadProc(__in  LPVOID lpParameter) 
{ 
    Sleep(50); 
    g_nNum++; 
    Sleep(0); 
    printf("當前計數為:%d\n",g_nNum); 
    return 0; 
}
複製程式碼

執行2次結果:

image

image

用了關鍵區域的情況:

複製程式碼
#include <stdio.h> 
#include <windows.h>

long g_nNum = 0 ; 
DWORD WINAPI ThreadProc(__in  LPVOID lpParameter); 
const int THREAD_NUM = 10;

CRITICAL_SECTION g_ThreadCode;

int main() 
{

    HANDLE  handle[THREAD_NUM];    
    g_nNum = 0; 
    int var = 0; 
    InitializeCriticalSection(&g_ThreadCode); 
    while ( var< THREAD_NUM) 
    { 
        handle[ var++] = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL); 
    } 
    WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE); 
    DeleteCriticalSection( &g_ThreadCode ); 
    
    for( var=0; var<sizeof(handle); var++) 
    { 
        CloseHandle(handle[var]); 
    }

    return 0; 
}

DWORD WINAPI ThreadProc(__in  LPVOID lpParameter) 
{  
    EnterCriticalSection( &g_ThreadCode ); 
    g_nNum++;  
    printf("當前計數為:%d\n",g_nNum); 
    LeaveCriticalSection( &g_ThreadCode ); 
    return 0; 
}
複製程式碼