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

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

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

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

互斥變量 

互斥對(duì)象包含一個(gè)使用數(shù)量,一個(gè)線程ID和一個(gè)計(jì)數(shù)器。其中線程ID用于標(biāo)識(shí)系統(tǒng)中的哪個(gè)線程當(dāng)前擁有互斥對(duì)象,計(jì)數(shù)器用于指明該線程擁有互斥對(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ù)。線程必須主動(dòng)請(qǐng)求共享對(duì)象的所有權(quán)才能獲得所有權(quán)。

釋放指定互斥對(duì)象的所有權(quán):調(diào)用ReleaseMutex函數(shù)。線程訪問共享資源結(jié)束后,線程要主動(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è)線程函數(shù)對(duì)這個(gè)變量進(jìn)行+1操作,執(zhí)行50000次;另一個(gè)線程函數(shù)對(duì)這個(gè)變量-1操作,執(zhí)行50000次。兩個(gè)線程函數(shù)各創(chuàng)建25個(gè)。因?yàn)槲覀兪褂昧嘶コ庾兞浚?0個(gè)線程會(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ì)象有兩種類型:人工重置的事件對(duì)象和自動(dòng)重置的事件對(duì)象。這兩種事件對(duì)象的區(qū)別在于當(dāng)人工重置的事件對(duì)象得到通知時(shí),等待該事件對(duì)象的所有線程均變?yōu)榭烧{(diào)度線程;而當(dāng)一個(gè)自動(dòng)重置的事件對(duì)象得到通知時(shí),等待該事件對(duì)象的線程中只有一個(gè)線程變?yōu)榭烧{(diào)度線程。

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

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

HANDLE CreateEvent(   
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全屬性   
BOOL bManualReset,   // 復(fù)位方式  TRUE 必須用ResetEvent手動(dòng)復(fù)原  FALSE 自動(dòng)還原為無信號(hào)狀態(tài)
BOOL bInitialState,   // 初始狀態(tài)   TRUE 初始狀態(tài)為有信號(hào)狀態(tài)  FALSE 無信號(hào)狀態(tài)
LPCTSTR lpName     //對(duì)象名稱  NULL  無名的事件對(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為無信號(hào)
  • 第四個(gè)參數(shù)表示對(duì)象名稱,NULL表示無名的事件對(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è)置為無信號(hào)狀態(tài)。

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

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

代碼示例 

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

#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;
 
//火車站賣票
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買了一張票,剩余%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買了一張票,剩余%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)用來解決并發(fā)中的互斥和同步問題的一種方法。與互斥量不同的地方是,它允許多個(gè)線程在同一時(shí)刻訪問同一資源,但是需要限制在同一時(shí)刻訪問此資源的最大線程數(shù)目。

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

HANDLE    WINAPI    
CreateSemaphoreW(
    _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  // Null 安全屬性
    _In_ LONG lInitialCount,  //初始化時(shí),共有多少個(gè)資源是可以用的。 0:未觸發(fā)狀//態(tài)(無信號(hào)狀態(tài)),表示沒有可用資源
    _In_ LONG lMaximumCount,  //能夠處理的最大的資源數(shù)量   3
    _In_opt_ LPCWSTR lpName   //NULL 信號(hào)量的名稱
);
  • 第一個(gè)參數(shù)表示安全屬性,這是創(chuàng)建內(nèi)核對(duì)象函數(shù)都會(huì)有的參數(shù),NULL表示默認(rèn)安全屬性
  • 第二個(gè)參數(shù)表示初始時(shí)有多少個(gè)資源可用,0表示無任何資源(未觸發(fā)狀態(tài))
  • 第三個(gè)參數(shù)表示最大資源數(shù)
  • 第四個(gè)參數(shù)表示信號(hào)量的名稱,NULL表示無名稱的信號(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。線程中的for循環(huán)每執(zhí)行一次會(huì)將另一個(gè)要申請(qǐng)的信號(hào)資源的可用資源數(shù)+1。因此程序的執(zhí)行結(jié)果為兩個(gè)線程中的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);//初始值沒有可用資源
    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;
}

用戶態(tài)

關(guān)鍵代碼

關(guān)鍵代碼段,也稱為臨界區(qū),工作在用戶方式下。它是指一個(gè)小代碼段,在代碼能夠執(zhí)行前,它必須獨(dú)占對(duì)某些資源的訪問權(quá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)體類型的對(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)用線程,則該函數(shù)就返回;否則該函數(shù)會(huì)一直等待,從而導(dǎo)致線程等待。

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

VOID
WINAPI
LeaveCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

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

4.刪除臨界區(qū)

WINBASEAPI
VOID
WINAPI
DeleteCriticalSection(
    _Inout_ LPCRITICAL_SECTION lpCriticalSection
);

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

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

下面這段程序同樣也是火車售票,其工作邏輯與上面的事件對(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買了一張票,剩余票數(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買了一張票,剩余票數(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)線程同步的四種方式總結(jié)的文章就介紹到這了,更多相關(guān)C++線程同步方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 概率的問題:使用遞歸與多次試驗(yàn)?zāi)M的分析

    概率的問題:使用遞歸與多次試驗(yàn)?zāi)M的分析

    以下對(duì)概率的問題:使用了遞歸和多次試驗(yàn)?zāi)M。需要的朋友參考下
    2013-05-05
  • 如何通過指針突破C++類的訪問權(quán)限

    如何通過指針突破C++類的訪問權(quán)限

    這篇文章主要介紹了通過指針突破C++類的訪問權(quán)限,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 關(guān)于C++智能指針shared_ptr和unique_ptr能否互轉(zhuǎn)問題

    關(guān)于C++智能指針shared_ptr和unique_ptr能否互轉(zhuǎn)問題

    C++中的智能指針最常用的是shared_ptr和unique_ptr,C++新手最常問的問題是我從一個(gè)函數(shù)中拿到unique_ptr,但要轉(zhuǎn)成shared_ptr才能使用,要怎么轉(zhuǎn)換?同理是否能將shared_ptr轉(zhuǎn)換成unique_ptr,面對(duì)這些問題,跟隨小編一起看看吧
    2022-05-05
  • c++中引用作為形參的使用方法以及作用

    c++中引用作為形參的使用方法以及作用

    這篇文章主要給大家介紹了關(guān)于c++中引用作為形參的使用方法以及作用的相關(guān)資料,引用是地址傳值,作為引用的形參數(shù)值被修改的同時(shí),也修改了對(duì)應(yīng)實(shí)參的值,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • C語言最大公約數(shù)示例教程

    C語言最大公約數(shù)示例教程

    這篇文章主要為大家介紹了C語言最大公約數(shù)的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-11-11
  • C語言數(shù)組越界引發(fā)的死循環(huán)問題解決

    C語言數(shù)組越界引發(fā)的死循環(huán)問題解決

    本文主要介紹了C語言數(shù)組越界引發(fā)的死循環(huán)問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Vc++ 控件List Control用法總結(jié)

    Vc++ 控件List Control用法總結(jié)

    這篇文章主要介紹了Vc++ 控件List Control用法總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2015-06-06
  • C++強(qiáng)制類型轉(zhuǎn)換的四種方式

    C++強(qiáng)制類型轉(zhuǎn)換的四種方式

    本文主要介紹了C++強(qiáng)制類型轉(zhuǎn)換的四種方式,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C語言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù)詳解

    C語言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù)詳解

    這篇文章主要為大家詳細(xì)介紹了C語言的動(dòng)態(tài)內(nèi)存分配及動(dòng)態(tài)內(nèi)存分配函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 怎么通過C語言自動(dòng)生成MAC地址

    怎么通過C語言自動(dòng)生成MAC地址

    以下是對(duì)使用C語言自動(dòng)生成MAC地址的實(shí)現(xiàn)代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下
    2013-09-09

最新評(píng)論