C++多線程同步之臨界區(CriticalSection)

一、Win32平臺

1、相關頭文件和接口

#include <windows.h>

CRITICAL_SECTION cs;//定義臨界區對象
InitializeCriticalSection(&cs);//初始化臨界區
EnterCriticalSection(&cs);//進入臨界區
LeaveCriticalSection(&cs);//離開臨界區
DeleteCriticalSection(&cs);//刪除臨界區

2、Win32源碼

//=====================MyCriticalSection.h===========================
#ifndef _My_CRITICAL_SECTION_H
#define _My_CRITICAL_SECTION_H

#include <windows.h>
//對臨界區同樣進行封裝
class CMyCriticalSection
{
public:
    CMyCriticalSection()
    {
        InitializeCriticalSection(&m_cSection);
    }

    void Lock()
    {
        EnterCriticalSection(&m_cSection);
    }

    void UnLock()
    {
        LeaveCriticalSection(&m_cSection);
    }


    //利用析構函數刪除臨界區對象
    virtual ~CMyCriticalSection()
    {
        DeleteCriticalSection(&m_cSection);
    }
private:
    CRITICAL_SECTION                        m_cSection;
};

class CCriticalSectionAutoLock
{
public:
    //利用構造函數上鎖,即進去臨界區
    CCriticalSectionAutoLock(CMyCriticalSection *mySection)
    :pCMySection(mySection)
    {
        pCMySection->Lock();
    }

    //利用析構函數解鎖,即離開臨界區
    virtual ~CCriticalSectionAutoLock()
    {
        pCMySection->UnLock();
    }
private:
    CMyCriticalSection                      *pCMySection;
};

#endif
#include <iostream>
#include <windows.h>
#include "MySemaphore.h"
#include "MyMutex.h"
#include "MyCriticalSection.h"
using namespace std;

//HANDLE g_hSemaphore = NULL;
//HANDLE g_hMutex = NULL;

CMySemaphore                    MySemaphore;            //信號量
CMyMutex                        MyMutex;                //互斥量
CMyCriticalSection              MyCriticalSection;      //臨界區

DWORD WINAPI Fun(LPVOID lpParamter)
{
    string strPrint((const char*)lpParamter);
    int iRunTime = 0;
    //執行100次跳出
    while(++iRunTime<10)
    {
        {
            CCriticalSectionAutoLock  cLock(&MyCriticalSection);
            cout <<"["<< iRunTime <<"]:"<< strPrint.c_str()<<endl;
        }
        Sleep(1); //若去掉此句 可能導致其他線程無法進入臨界區,因爲 cLock在這之前析構,離開臨界區

    }
    return 0;
}

int main()
{
    //創建五個子線程
    string str1 = "A";
    string str2 = "B";
    string str3 = "C";
    string str4 = "D";
    string str5 = "E";

    HANDLE hThread1 = CreateThread(NULL, 0, Fun, (void*)str1.c_str(), 0, NULL);
    HANDLE hThread2 = CreateThread(NULL, 0, Fun, (void*)str2.c_str(), 0, NULL);
    HANDLE hThread3 = CreateThread(NULL, 0, Fun, (void*)str3.c_str(), 0, NULL);
    HANDLE hThread4 = CreateThread(NULL, 0, Fun, (void*)str4.c_str(), 0, NULL);
    HANDLE hThread5 = CreateThread(NULL, 0, Fun, (void*)str5.c_str(), 0, NULL);

    //關閉線程
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    CloseHandle(hThread3);
    CloseHandle(hThread4);
    CloseHandle(hThread5);

    getchar();
//  system("pause");
    return 0;
}

執行結果:這裏寫圖片描述
這是加上Sleep(1);的運行結果,沒有加上Sleep(1);的執行結果如下:
這裏寫圖片描述
從結果我們可以看出如果沒有加上Sleep(1),即在離開臨界區後進行休眠,其他線程進入臨界區的概率會大大降低,原因可能是由於While循環在不停的循環時,其他線程還沒有那麼快能夠進入臨界區,因此在這種情況下想讓所有的線程都有機會進入臨界區,則需要在離開臨界區之後做短暫休眠即可。

3、Linux平臺

在Linux環境下,沒有Windows下的臨界區的概念,但是也可以利用互斥量實現該功能。Linux下的API如下,在前面的博文裏也有講到過,可以參考http://blog.csdn.net/olansefengye1/article/details/53086141

include <pthread.h>
int pthread_mutexattr_init(pthread_mutexattr_t *attr); /*初始化函數*/
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);/*去初始化函數*/

int pthread_mutex_lock(pthread_mutexattr_t *attr)/*加鎖*/
int pthread_mutex_unlock(pthread_mutexattr_t *attr)/*解鎖*/

但是兩者並不是完全一樣的,他們的區別總結如下:
1、臨界區只能用於對象在同一進程裏線程間的互斥訪問;互斥體可以用於對象進程間或線程間的互斥訪問。
2、臨界區是非內核對象,只在用戶態進行鎖操作,速度快;互斥體是內核對象,在覈心態進行鎖操作,速度慢。
3、臨界區和互斥體在Windows平臺都下可用;Linux下只有互斥體可用。
4、臨界區:通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。
5、互斥量:爲協調共同對一個共享資源的單獨訪問而設計的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章