C++线程同步总结(笔记)

C++线程同步总结(笔记)

Dec 26, 2013
Coding
C++, Thread, Mutex

主要有四种方式:临界区(CRITICAL_SECTION)、互斥对象(Mutex,Mutual Exclusion)、事件对象(Event)、信号量(Semaphore)。

其中临界区效率最高,但只能实现本进程内的线程同步。其它三个可以实现多个进程内的线程同步。信号量功能最强大可实现线程互斥也可以用于共享的多个资源访问控制。

Windows中,Mutex和CRITICAL_SECTION是两种使用了不同API的互斥量。两者的差别在于,Windows的标准Mutex对象是一种内核机制,它的使用需要从用户模式切换到内核模式,可以实现跨进程的同步。CRITICAL_SECTION是用户级互斥量,加快了锁操作过程。

临界区使用方式如下

CRITICAL_SECTION cs;//临界区
InitializeCriticalSection(&cs); //初始化临界区

EnterCriticalSection(&cs);                 //进入临界区
//访问互斥共享资源的代码
LeaveCriticalSection(&cs);                 //离开临界区

事件的使用方式如下

//初始化
HANDLE h = CreateEvent(NULL,FALSE,TRUE,NULL);//线程同步时使用自动重置事件,初始状态可设为有信号

//使用
DWORD nWaitResult = WaitForSingleObject(h,INFINITE);//等待信号,等到后会自动设置为无信号
//ResetEvent(h);//设置为无信号,防止其他线程访问
  //访问资源的代码
SetEvent();   //设置为有信号,其他线程可访问 

互斥对象和信号量的使用方式如下

//初始化
HANDLE h = CreateXXX();//CreateMutex,CreateSemaphore

//使用
DWORD nWaitResult = WaitForSingleObject(h,INFINITE);//等待信号
  //访问资源的代码
ReleaseXXX();//ReleaseMutex(),ReleaseSemaphore(),释放资源

具体示例代码 #

利用临界区 CRITICAL_SECTION #

#include <iostream.h>
#include <windows.h>

DWORD WINAPI Fun1Proc(
    LPVOID lpParameter
);
DWORD WINAPI Fun2Proc(
    LPVOID lpParameter
);

int tickets = 100;
CRITICAL_SECTION cs;//临界区

int main()
{
    InitializeCriticalSection(&cs); //初始化临界区

    HANDLE hThread1,hThread2;
    hThread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);

    Sleep(8000);
    return 1;
}

DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    while (TRUE){
        EnterCriticalSection(&cs); //进入临界区

        if(0 == tickets){
            LeaveCriticalSection(&cs);
            break;
        }
        cout<<"Thread1 sell tickets "<<tickets--<<endl;

        LeaveCriticalSection(&cs); //离开临界区
    }
    return 0;
}

DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
    while (TRUE){
        EnterCriticalSection(&cs); //进入临界区

        if(0 == tickets){
            LeaveCriticalSection(&cs);
            break;
        }
        cout<<"Thread2 sell tickets "<<tickets--<<endl;

        LeaveCriticalSection(&cs); //离开临界区
    }
    return 0;
}

利用互斥对象Mutex #

#include <iostream.h>
#include <windows.h>

DWORD WINAPI Fun1Proc(
    LPVOID lpParameter
);

DWORD WINAPI Fun2Proc(
    LPVOID lpParameter
);

int tickets = 100;
HANDLE hMutex; //互斥对象

int main()
{
    HANDLE hThread1,hThread2;
    hThread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    hMutex = CreateMutex(NULL,FALSE,NULL);

    Sleep(8000);
    return 1;
}

DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    while (TRUE){
    WaitForSingleObject(hMutex,INFINITE); //有信号时才返回
    if(0 == tickets){
        ReleaseMutex(hMutex);
        break;
    }
    cout<<"Thread1 sell tickets "<<tickets--<<endl;
    ReleaseMutex(hMutex);//释放互斥对象
    }
    return 0;
}

DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
    while (TRUE){
    WaitForSingleObject(hMutex,INFINITE); //有信号时才返回
    if(0 == tickets){
        ReleaseMutex(hMutex);
        break;
    }
    cout<<"Thread2 sell tickets "<<tickets--<<endl;
    ReleaseMutex(hMutex);//释放互斥对象
    }
    return 0;
}

利用事件Event #

#include <iostream.h>
#include <windows.h>

DWORD WINAPI Fun1Proc(
    LPVOID lpParameter
);

DWORD WINAPI Fun2Proc(
    LPVOID lpParameter
);

int tickets = 100;
HANDLE hEvent; //事件

int main()
{
    hEvent = CreateEvent(NULL,FALSE,FALSE,NULL); //创建事件,自动重置,初始无信号
    SetEvent(hEvent);//设置成有信号状态
    HANDLE hThread1,hThread2;
    hThread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);

    Sleep(8000);
    return 1;
}

DWORD WINAPI Fun1Proc(LPVOID lpParameter    )
{
    while (TRUE){
        WaitForSingleObject(hEvent,INFINITE); //事件有信号才返回
        //ResetEvent(hEvent); //设成无信号,以免其余线程访问
        if(0 == tickets)
            break;
        cout<<"Thread1 sell tickets "<<tickets--<<endl;
        SetEvent(hEvent);//设为有信号,以供其余线程调用
    }
    return 0;
}

DWORD WINAPI Fun2Proc(LPVOID lpParameter    )
{
    while (TRUE){
        WaitForSingleObject(hEvent,INFINITE); //事件有信号才返回
        //ResetEvent(hEvent); //设成无信号,以免其余线程访问
        if(0 == tickets)
            break;
        cout<<"Thread2 sell tickets "<<tickets--<<endl;
        SetEvent(hEvent);//设为有信号,以供其余线程调用
    }
    return 0;
}

利用信号量Semaphore #

/*
* FileName: Semaphore_Test.cpp
* Author: JarvisChu
* Date: 2012-11-22
*/

//#include <iostream>
#include <iostream>
#include <windows.h>

using namespace std;

DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
DWORD WINAPI Fun3Proc(LPVOID lpParameter);

volatile int tickets = 100;
HANDLE hSemaphore;

int main()
{
    //必须先Create Semaphore 然后CreateThread

    hSemaphore = CreateSemaphore( NULL,
                                                      1,//初始资源数 互斥的情况下必须为1
                                                      3,//最大资源数,互斥的情况下意义不大
                                                      NULL //Unnameed semaphore
                          );
    if(hSemaphore == NULL) cout<<"Create Semaphore Failed!"<<endl;

    HANDLE hThread1,hThread2,hThread3;
    hThread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    hThread3 = CreateThread(NULL,0,Fun3Proc,NULL,0,NULL);

    CloseHandle(hThread1);
    CloseHandle(hThread2);
    CloseHandle(hThread3);

    Sleep(800);
    return 0;
}

DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
    while (TRUE)
    {
        DWORD nWaitResult;
        nWaitResult = WaitForSingleObject(hSemaphore,INFINITE);

        if(tickets >0)
            cout<<"Thread2 Sailed ticket "<<tickets--<<endl;
        else
            break;
        ReleaseSemaphore(hSemaphore,1,NULL);
    }
    return 0;
}
DWORD WINAPI Fun3Proc(LPVOID lpParameter)
{
    while (TRUE)
    {
        DWORD nWaitResult;
        nWaitResult = WaitForSingleObject(hSemaphore,INFINITE);

        if(tickets >0)
            cout<<"Thread3 Sailed ticket "<<tickets--<<endl;
        else
            break;
        ReleaseSemaphore(hSemaphore,1,NULL);
    }
    return 0;
}

该文2010-08-06 16:34首发于我的CSDN专栏。有改动。