欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++實(shí)現(xiàn)線(xiàn)程同步的四種方式總結(jié)

 更新時(shí)間:2022年11月11日 08:54:31   作者:霸道小明  
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)線(xiàn)程同步的四種方式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定的幫助,需要的可以參考一下

內(nèi)核態(tài)

互斥變量 

互斥對(duì)象包含一個(gè)使用數(shù)量,一個(gè)線(xiàn)程ID和一個(gè)計(jì)數(shù)器。其中線(xiàn)程ID用于標(biāo)識(shí)系統(tǒng)中的哪個(gè)線(xiàn)程當(dāng)前擁有互斥對(duì)象,計(jì)數(shù)器用于指明該線(xiàn)程擁有互斥對(duì)象的次數(shù)。

創(chuàng)建互斥對(duì)象:調(diào)用函數(shù)CreateMutex。調(diào)用成功,該函數(shù)返回所創(chuàng)建的互斥對(duì)象的句柄。

請(qǐng)求互斥對(duì)象所有權(quán):調(diào)用函數(shù)WaitForSingleObject函數(shù)。線(xiàn)程必須主動(dòng)請(qǐng)求共享對(duì)象的所有權(quán)才能獲得所有權(quán)。

釋放指定互斥對(duì)象的所有權(quán):調(diào)用ReleaseMutex函數(shù)。線(xiàn)程訪(fǎng)問(wèn)共享資源結(jié)束后,線(xiàn)程要主動(dòng)釋放對(duì)互斥對(duì)象的所有權(quán),使該對(duì)象處于已通知狀態(tài)。

創(chuàng)建互斥對(duì)象函數(shù)

HANDLE
WINAPI
CreateMutexW(
    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,   //指向安全屬性
    _In_ BOOL bInitialOwner,   //初始化互斥對(duì)象的所有者  TRUE 立即擁有互斥體
    _In_opt_ LPCWSTR lpName    //指向互斥對(duì)象名的指針  L“Bingo”
);
  • 第一個(gè)參數(shù)表示安全屬性,這是每一個(gè)創(chuàng)建內(nèi)核對(duì)象都會(huì)有的參數(shù),NULL表示默認(rèn)安全屬性
  • 第二個(gè)參數(shù)表示互斥對(duì)象所有者,TRUE立即擁有互斥體
  • 第三個(gè)參數(shù)表示指向互斥對(duì)象的指針 

代碼示例

下面這段程序聲明了一個(gè)全局整型變量,并初始化為0。一個(gè)線(xiàn)程函數(shù)對(duì)這個(gè)變量進(jìn)行+1操作,執(zhí)行50000次;另一個(gè)線(xiàn)程函數(shù)對(duì)這個(gè)變量-1操作,執(zhí)行50000次。兩個(gè)線(xiàn)程函數(shù)各創(chuàng)建25個(gè)。因?yàn)槲覀兪褂昧嘶コ庾兞浚?0個(gè)線(xiàn)程會(huì)按照一定順序?qū)@變量操作,因此最后結(jié)果為0。 

#include <stdio.h>
#include <windows.h>
#include <process.h>
 
#define NUM_THREAD    50
unsigned WINAPI threadInc(void* arg);
unsigned WINAPI threadDes(void* arg);
long long num = 0;
HANDLE hMutex;
 
int main() {
    //內(nèi)核對(duì)象數(shù)組
    HANDLE tHandles[NUM_THREAD];
    int i;
    //創(chuàng)建互斥信號(hào)量
    hMutex = CreateMutex(0, FALSE, NULL);
    printf("sizeof long long: %d \n", sizeof(long long));
    for (i = 0; i < NUM_THREAD; i++) {
        if (i % 2)
            tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
        else
            tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
    }
 
    WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
    //關(guān)閉互斥對(duì)象
    CloseHandle(hMutex);
    printf("result: %lld \n", num);
    return 0;
}
 
unsigned WINAPI threadInc(void* arg){
    int i;
    //請(qǐng)求使用
    WaitForSingleObject(hMutex, INFINITE);
    for (i = 0; i < 500000; i++)
        num += 1;
    //釋放
    ReleaseMutex(hMutex);
    return 0;
}
unsigned WINAPI threadDes(void* arg){
    int i;
    //請(qǐng)求
    WaitForSingleObject(hMutex, INFINITE);
    for (i = 0; i < 500000; i++)
        num -= 1;
    //釋放
    ReleaseMutex(hMutex);
    return 0;
}

事件對(duì)象

事件對(duì)象也屬于內(nèi)核對(duì)象,它包含以下三個(gè)成員:

  • 使用計(jì)數(shù);
  • 用于指明該事件是一個(gè)自動(dòng)重置的事件還是一個(gè)人工重置的事件的布爾值;
  • 用于指明該事件處于已通知狀態(tài)還是未通知狀態(tài)的布爾值。

事件對(duì)象有兩種類(lèi)型:人工重置的事件對(duì)象和自動(dòng)重置的事件對(duì)象。這兩種事件對(duì)象的區(qū)別在于當(dāng)人工重置的事件對(duì)象得到通知時(shí),等待該事件對(duì)象的所有線(xiàn)程均變?yōu)榭烧{(diào)度線(xiàn)程;而當(dāng)一個(gè)自動(dòng)重置的事件對(duì)象得到通知時(shí),等待該事件對(duì)象的線(xiàn)程中只有一個(gè)線(xiàn)程變?yōu)榭烧{(diào)度線(xiàn)程。

1.創(chuàng)建事件對(duì)象

調(diào)用CreateEvent函數(shù)創(chuàng)建或打開(kāi)一個(gè)命名的或匿名的事件對(duì)象。

HANDLE CreateEvent(   
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全屬性   
BOOL bManualReset,   // 復(fù)位方式  TRUE 必須用ResetEvent手動(dòng)復(fù)原  FALSE 自動(dòng)還原為無(wú)信號(hào)狀態(tài)
BOOL bInitialState,   // 初始狀態(tài)   TRUE 初始狀態(tài)為有信號(hào)狀態(tài)  FALSE 無(wú)信號(hào)狀態(tài)
LPCTSTR lpName     //對(duì)象名稱(chēng)  NULL  無(wú)名的事件對(duì)象 
);
  • 第一個(gè)參數(shù)表示安全屬性,這是創(chuàng)建內(nèi)核對(duì)象函數(shù)都有的一個(gè)參數(shù),NULL表示默認(rèn)安全屬性
  • 第二個(gè)參數(shù)表示復(fù)位方式,如果是TRUE,則必須手動(dòng)調(diào)用ResetEvent函數(shù)復(fù)位,F(xiàn)ALSE則表示自動(dòng)還原
  • 第三個(gè)參數(shù)表示初始狀態(tài),TRUE表示初始為有信號(hào)狀態(tài),F(xiàn)ALSE為無(wú)信號(hào)
  • 第四個(gè)參數(shù)表示對(duì)象名稱(chēng),NULL表示無(wú)名的事件對(duì)象

2. 設(shè)置事件對(duì)象狀態(tài)

調(diào)用SetEvent函數(shù)把指定的事件對(duì)象設(shè)置為有信號(hào)狀態(tài)。

3. 重置事件對(duì)象狀態(tài)

調(diào)用ResetEvent函數(shù)把指定的事件對(duì)象設(shè)置為無(wú)信號(hào)狀態(tài)。

4. 請(qǐng)求事件對(duì)象

 線(xiàn)程通過(guò)調(diào)用WaitForSingleObject函數(shù)請(qǐng)求事件對(duì)象。

代碼示例 

下面這段程序是一段火車(chē)售票:線(xiàn)程A和B會(huì)不停的購(gòu)票直到票數(shù)小于0,執(zhí)行完畢。在判斷票數(shù)前會(huì)先申請(qǐng)事件對(duì)象,購(gòu)票結(jié)束或者票數(shù)小于0時(shí)則會(huì)釋放事件對(duì)象(事件對(duì)象置位有信號(hào))。因?yàn)槲覀兪褂昧耸录?duì)象。兩個(gè)線(xiàn)程會(huì)按某一順序購(gòu)票,直到票數(shù)小于0。

#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;
 
//火車(chē)站賣(mài)票
int iTickets = 100;//總票數(shù)
HANDLE g_hEvent;
 
 
unsigned WINAPI SellTicketA(void* lpParam) {
 
    while (true) {
        WaitForSingleObject(g_hEvent, INFINITE);
        if (iTickets > 0) {
            Sleep(1);
            printf("A買(mǎi)了一張票,剩余%d\n", iTickets--);
        }
        else {
            SetEvent(g_hEvent);
            break;
        }
        SetEvent(g_hEvent);
    }
    return 0;
}
 
unsigned WINAPI SellTicketB(void* lpParam) {
    while (true) {
        WaitForSingleObject(g_hEvent, INFINITE);
        if (iTickets > 0) {
            Sleep(1);
            printf("B買(mǎi)了一張票,剩余%d\n", iTickets--);
        }
        else {
            SetEvent(g_hEvent);
            break;
        }
        SetEvent(g_hEvent);
    }
    return 0;
}
 
int main() {
 
    HANDLE hThreadA, hThreadB;
    hThreadA = (HANDLE)_beginthreadex(NULL, 0, SellTicketA, NULL, 0, NULL);
    hThreadB = (HANDLE)_beginthreadex(NULL, 0, SellTicketB, NULL, 0, NULL);
 
    CloseHandle(hThreadA);
    CloseHandle(hThreadB); 
 
    g_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    SetEvent(g_hEvent);
    Sleep(4000);
    CloseHandle(g_hEvent);
    system("pause");
    return 0;
}

資源信號(hào)量

信號(hào)量(semaphore)是操作系統(tǒng)用來(lái)解決并發(fā)中的互斥和同步問(wèn)題的一種方法。與互斥量不同的地方是,它允許多個(gè)線(xiàn)程在同一時(shí)刻訪(fǎng)問(wèn)同一資源,但是需要限制在同一時(shí)刻訪(fǎng)問(wèn)此資源的最大線(xiàn)程數(shù)目。

創(chuàng)建信號(hào)量函數(shù)

HANDLE    WINAPI    
CreateSemaphoreW(
    _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  // Null 安全屬性
    _In_ LONG lInitialCount,  //初始化時(shí),共有多少個(gè)資源是可以用的。 0:未觸發(fā)狀//態(tài)(無(wú)信號(hào)狀態(tài)),表示沒(méi)有可用資源
    _In_ LONG lMaximumCount,  //能夠處理的最大的資源數(shù)量   3
    _In_opt_ LPCWSTR lpName   //NULL 信號(hào)量的名稱(chēng)
);
  • 第一個(gè)參數(shù)表示安全屬性,這是創(chuàng)建內(nèi)核對(duì)象函數(shù)都會(huì)有的參數(shù),NULL表示默認(rèn)安全屬性
  • 第二個(gè)參數(shù)表示初始時(shí)有多少個(gè)資源可用,0表示無(wú)任何資源(未觸發(fā)狀態(tài))
  • 第三個(gè)參數(shù)表示最大資源數(shù)
  • 第四個(gè)參數(shù)表示信號(hào)量的名稱(chēng),NULL表示無(wú)名稱(chēng)的信號(hào)量對(duì)象

增加/釋放信號(hào)量

ReleaseSemaphore(
    _In_ HANDLE hSemaphore,   //信號(hào)量的句柄
    _In_ LONG lReleaseCount,   //將lReleaseCount值加到信號(hào)量的當(dāng)前資源計(jì)數(shù)上面 0-> 1
    _Out_opt_ LPLONG lpPreviousCount  //當(dāng)前資源計(jì)數(shù)的原始值
);
  • 第一個(gè)參數(shù)表示信號(hào)量句柄,也就是調(diào)用創(chuàng)建信號(hào)量函數(shù)時(shí)返回的句柄
  • 第二個(gè)參數(shù)表示釋放的信號(hào)量個(gè)數(shù),該值必須大于0,但不能大于信號(hào)量的最大計(jì)數(shù)
  • 第三個(gè)參數(shù)表示指向要接收信號(hào)量的上一個(gè)計(jì)數(shù)的變量的指針。如果不需要上一個(gè)計(jì)數(shù), 則此參數(shù)可以為NULL 。

關(guān)閉句柄

CloseHandle(
    _In_ _Post_ptr_invalid_ HANDLE hObject
);

代碼示例

下面這段程序創(chuàng)建了兩個(gè)信號(hào)資源,其最大資源都為1;一個(gè)初始資源為0,另一個(gè)初始資源為1。線(xiàn)程中的for循環(huán)每執(zhí)行一次會(huì)將另一個(gè)要申請(qǐng)的信號(hào)資源的可用資源數(shù)+1。因此程序的執(zhí)行結(jié)果為兩個(gè)線(xiàn)程中的for循環(huán)交替執(zhí)行。

#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;
 
static HANDLE semOne;
static HANDLE semTwo;
static int num;
 
/*
* 信號(hào)資源semOne初始為0,最大1個(gè)資源可用
* 信號(hào)資源semTwo初始為1,最大1個(gè)資源可用
*/
 
unsigned WINAPI Read(void* arg) {
    int i;
    for (i = 0; i < 5; i++) {
        fputs("Input num:\n", stdout);
        printf("begin read\n");
        WaitForSingleObject(semTwo, INFINITE);
        printf("beginning read\n");
        scanf("%d", &num);
        ReleaseSemaphore(semOne, 1, NULL);
    }
    return 0;
}
 
unsigned WINAPI Accu(void* arg) {
    int sum = 0, i;
    for (i = 0; i < 5; ++i) {
        printf("begin Accu\n");
        WaitForSingleObject(semOne, INFINITE);
        printf("beginning Accu\n");
        sum += num;
        printf("sum=%d\n", sum);
        ReleaseSemaphore(semTwo, 1, NULL);
    }
    return 0;    
}
 
int main() {
    HANDLE hThread1, hThread2;
    semOne = CreateSemaphore(NULL, 0, 1, NULL);//初始值沒(méi)有可用資源
    semTwo = CreateSemaphore(NULL, 1, 1, NULL);//初始值有一個(gè)可用資源
 
 
    hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);
    hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);
    WaitForSingleObject(hThread1, INFINITE);
    WaitForSingleObject(hThread2, INFINITE);
 
    CloseHandle(semOne);
    CloseHandle(semTwo);
    system("pause");
    return 0;
}

用戶(hù)態(tài)

關(guān)鍵代碼

關(guān)鍵代碼段,也稱(chēng)為臨界區(qū),工作在用戶(hù)方式下。它是指一個(gè)小代碼段,在代碼能夠執(zhí)行前,它必須獨(dú)占對(duì)某些資源的訪(fǎng)問(wèn)權(quán)。通常把多線(xiàn)程中訪(fǎng)問(wèn)同一種資源的那部分代碼當(dāng)做關(guān)鍵代碼段。

1.初始化關(guān)鍵代碼段

調(diào)用InitializeCriticalSection函數(shù)初始化一個(gè)關(guān)鍵代碼段

InitialzieCriticalSection(
    _Out_ LPRRITICAL_SECTION lpCriticalSection
);

該函數(shù)只有一個(gè)指向CRITICAL_SECTION結(jié)構(gòu)體的指針。在調(diào)用InitializeCriticalSection函數(shù)之前,首先需要構(gòu)造一個(gè)CRITICAL_SCTION結(jié)構(gòu)體類(lèi)型的對(duì)象,然后將該對(duì)象的地址傳遞給InitializeCriticalSection函數(shù)。

2進(jìn)入關(guān)鍵代碼

VOID
WINAPI
EnterCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

調(diào)用EnterCriticalSection函數(shù),以獲得指定的臨界區(qū)對(duì)象的所有權(quán),該函數(shù)等待指定的臨界區(qū)對(duì)象的所有權(quán),如果該所有權(quán)賦予了調(diào)用線(xiàn)程,則該函數(shù)就返回;否則該函數(shù)會(huì)一直等待,從而導(dǎo)致線(xiàn)程等待。

3.退出關(guān)鍵代碼段

VOID
WINAPI
LeaveCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

線(xiàn)程使用完臨界區(qū)所保護(hù)的資源之后,需要調(diào)用LeaveCriticalSection函數(shù),釋放指定的臨界區(qū)對(duì)象的所有權(quán)。之后,其他想要獲得該臨界區(qū)對(duì)象所有權(quán)的線(xiàn)程就可以獲得該所有權(quán),從而進(jìn)入關(guān)鍵代碼段,訪(fǎng)問(wèn)保護(hù)的資源。

4.刪除臨界區(qū)

WINBASEAPI
VOID
WINAPI
DeleteCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

當(dāng)臨界區(qū)不再需要時(shí),可以調(diào)用DeleteCriticalSection函數(shù)釋放該對(duì)象,該函數(shù)將釋放一個(gè)沒(méi)有被任何線(xiàn)程所擁有的臨界區(qū)對(duì)象的所有資源。

程序?qū)嵗?/p>

下面這段程序同樣也是火車(chē)售票,其工作邏輯與上面的事件對(duì)象基本吻合。

#include<iostream>
#include<Windows.h>
#include<process.h> 
using namespace std;
 
int iTickets = 100;
CRITICAL_SECTION g_cs;
  
//A窗口
DWORD WINAPI SellTicketA(void* lpParam) {
    while (1) {
        EnterCriticalSection(&g_cs);//進(jìn)入臨界區(qū)
        if (iTickets > 0) {
            Sleep(1);
            iTickets--;
            printf("A買(mǎi)了一張票,剩余票數(shù)為:%d\n", iTickets);
            LeaveCriticalSection(&g_cs);
        }
        else {
            LeaveCriticalSection(&g_cs);
            break;
        }
    }
    return 0;
}
 
//B窗口
DWORD WINAPI SellTicketB(void* lpParam) {
    while (1) {
        EnterCriticalSection(&g_cs);
        if (iTickets > 0) {
            Sleep(1);
            iTickets--;
            printf("B買(mǎi)了一張票,剩余票數(shù)為:%d\n", iTickets);
            LeaveCriticalSection(&g_cs);
        }
        else {
            LeaveCriticalSection(&g_cs);
            break;
        }
    }
    return 0;
}
 
 
int main() {
    HANDLE hThreadA, hThreadB;
    hThreadA = CreateThread(NULL, 0, SellTicketA, NULL, 0, NULL);
    hThreadB = CreateThread(NULL, 0, SellTicketB, NULL, 0, NULL);
 
    CloseHandle(hThreadA);
    CloseHandle(hThreadB);
        
    InitializeCriticalSection(&g_cs);//初始化關(guān)鍵代碼
    Sleep(1000);
 
    DeleteCriticalSection(&g_cs);
    system("pause");
    return 0;
}

到此這篇關(guān)于C++實(shí)現(xiàn)線(xiàn)程同步的四種方式總結(jié)的文章就介紹到這了,更多相關(guān)C++線(xiàn)程同步方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論