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; 
}
复制代码

猜你喜欢

转载自www.cnblogs.com/cyblogs/p/9948471.html
今日推荐