国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux之信號(hào)量 | 消費(fèi)者生產(chǎn)者模型的循環(huán)隊(duì)列

這篇具有很好參考價(jià)值的文章主要介紹了Linux之信號(hào)量 | 消費(fèi)者生產(chǎn)者模型的循環(huán)隊(duì)列。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

一、信號(hào)量

1、概念

2、信號(hào)量操作函數(shù)

二、基于環(huán)形隊(duì)列的生產(chǎn)者消費(fèi)者模型

1、模型分析

2、代碼實(shí)現(xiàn)

1、單生產(chǎn)單消費(fèi)的生產(chǎn)者消費(fèi)者模型

2、多生產(chǎn)多消費(fèi)的生產(chǎn)者消費(fèi)者模型


一、信號(hào)量

1、概念

引入:前面我們講到了,對臨界資源進(jìn)行訪問時(shí),為了保證數(shù)據(jù)的一致性,我們需要對臨界資源進(jìn)行加鎖保護(hù)。當(dāng)我們用一個(gè)互斥鎖對臨界資源進(jìn)行保護(hù)時(shí),相當(dāng)于我們將這塊臨界資源看作一個(gè)整體,同一時(shí)刻只允許一個(gè)執(zhí)行流對這塊臨界資源進(jìn)行訪問。這樣做非常合理,但是效率太低了。

但是,我們最理想的方案,其實(shí)是:如果在同一時(shí)刻,不同的執(zhí)行流要訪問的是臨界資源的不同區(qū)域,那么我們是允許它們同時(shí)進(jìn)行臨界資源的訪問,這樣就大大提高了效率。

比如,如果一個(gè)臨界資源是一個(gè)大小為10數(shù)組,我們可以對其加鎖保護(hù)??墒?,現(xiàn)在來看,如果有10個(gè)線程同時(shí)訪問這個(gè)數(shù)組,可以嗎?當(dāng)然可以,只要這10個(gè)線程在同一時(shí)刻訪問的是數(shù)組的不同位置,即10個(gè)位置一個(gè)線程訪問一個(gè)。這樣我們就可以讓多個(gè)執(zhí)行流同時(shí)訪問臨界資源了。

這時(shí),我們就使用了信號(hào)量來幫助我們實(shí)現(xiàn)這個(gè)方案。

信號(hào)量:信號(hào)量的本質(zhì)是一個(gè)計(jì)數(shù)器,通常用來表示臨界資源中,資源數(shù)的多少。申請信號(hào)量實(shí)際上就是對臨界資源的預(yù)定機(jī)制。信號(hào)量主要用于同步和互斥。

每個(gè)執(zhí)行流在進(jìn)入臨界區(qū)之前都應(yīng)該先申請信號(hào)量,申請成功就有了訪問臨界資源的權(quán)限,當(dāng)訪問完畢后就應(yīng)該釋放信號(hào)量。?

信號(hào)量的PV操作:

~? P操作:我們將申請信號(hào)量稱為P操作。申請信號(hào)量的本質(zhì)就是申請獲得臨界資源中某塊資源的訪問權(quán)限,當(dāng)申請成功時(shí)臨界資源中資源的數(shù)目應(yīng)該減一,因此P操作的本質(zhì)就是讓信號(hào)量減一。

~? V操作:我們將釋放信號(hào)量稱為V操作。釋放信號(hào)量的本質(zhì)就是歸還臨界資源中某塊資源的訪問權(quán)限,當(dāng)釋放成功時(shí)臨界資源中資源的數(shù)目就應(yīng)該加一,因此V操作的本質(zhì)就是讓信號(hào)量加一。

2、信號(hào)量操作函數(shù)

sem_init:初始化信號(hào)量的函數(shù),該函數(shù)的函數(shù)原型如下:返回值,初始化信號(hào)量成功返回0,失敗返回-1。

NAME
       sem_init - initialize an unnamed semaphore

SYNOPSIS
       #include <semaphore.h>

       int sem_init(sem_t *sem, int pshared, unsigned int value);

       Link with -pthread.

參數(shù)說明:

sem:需要初始化的信號(hào)量。
pshared:傳入0值表示線程間共享,傳入非零值表示進(jìn)程間共享。
value:信號(hào)量的初始值。

sem_destroy:銷毀信號(hào)量的函數(shù),該函數(shù)的函數(shù)原型如下:

NAME
       sem_destroy - destroy an unnamed semaphore

SYNOPSIS
       #include <semaphore.h>

       int sem_destroy(sem_t *sem);

       Link with -pthread.

參數(shù)說明:sem:需要銷毀的信號(hào)量。
返回值:銷毀信號(hào)量成功返回0,失敗返回-1。

sem_wait:等待信號(hào)量(申請信號(hào)量)的函數(shù),該函數(shù)的函數(shù)原型如下:

NAME
       sem_wait, sem_timedwait, sem_trywait - lock a semaphore

SYNOPSIS
       #include <semaphore.h>

       int sem_wait(sem_t *sem);
       Link with -pthread.

參數(shù):sem:需要等待的信號(hào)量。
返回值:等待信號(hào)量成功返回0,信號(hào)量的值減一。等待信號(hào)量失敗返回-1,信號(hào)量的值保持不變。

sem_post:釋放信號(hào)量(發(fā)布信號(hào)量)的函數(shù),該函數(shù)的函數(shù)原型如下:

NAME
       sem_post - unlock a semaphore

SYNOPSIS
       #include <semaphore.h>

       int sem_post(sem_t *sem);

       Link with -pthread.

參數(shù):sem:需要釋放的信號(hào)量。
返回值:釋放信號(hào)量成功返回0,信號(hào)量的值加一。釋放信號(hào)量失敗返回-1,信號(hào)量的值保持不變。

有了對信號(hào)量的各種操作,我們下面來通過一個(gè)具體的例子來使用一下他們。

二、基于環(huán)形隊(duì)列的生產(chǎn)者消費(fèi)者模型

1、模型分析

Linux之信號(hào)量 | 消費(fèi)者生產(chǎn)者模型的循環(huán)隊(duì)列,Linux,開發(fā)語言,linux

實(shí)際上并不是真正的環(huán)形隊(duì)列,因?yàn)槲覀儧]有這種數(shù)據(jù)結(jié)構(gòu),它的實(shí)現(xiàn)是通過數(shù)組模擬的,當(dāng)數(shù)據(jù)加入到最后的位置時(shí)直接模等于數(shù)組的大小即可,這樣就可以回到數(shù)組的起始位置。

我們在對環(huán)形隊(duì)列進(jìn)行訪問時(shí),當(dāng)隊(duì)列為空或者為滿,生產(chǎn)者和消費(fèi)者就會(huì)指向同一個(gè)位置,這時(shí)我們就需要生產(chǎn)者和消費(fèi)者互斥和同步了,如果為空,讓生產(chǎn)者先訪問,為滿就讓消費(fèi)者先訪問。

而當(dāng)隊(duì)列不為空,也不為滿時(shí),生產(chǎn)者和消費(fèi)者可以訪問隊(duì)列不同的位置,以實(shí)現(xiàn)并發(fā)。這樣就可以提高效率了。

為了實(shí)現(xiàn)消費(fèi)者和生產(chǎn)者的并發(fā)訪問,我們需要使用信號(hào)量。我們使用信號(hào)量來表示隊(duì)列中相關(guān)資源的個(gè)數(shù)。

1、對于生產(chǎn)者,在意的是隊(duì)列中的空間資源,只要有空間生產(chǎn)者就可以進(jìn)行生產(chǎn)。空間資源定義成一個(gè)生產(chǎn)者需要的信號(hào)量(space_sem),在初始化時(shí),它的初始值我們應(yīng)該設(shè)置為環(huán)形隊(duì)列的容量,因?yàn)閯傞_始時(shí)環(huán)形隊(duì)列當(dāng)中全是空間。

2、對于消費(fèi)者,在意的是隊(duì)列中的數(shù)據(jù)資源,只要有數(shù)據(jù)消費(fèi)者就可以進(jìn)行消費(fèi)。數(shù)據(jù)資源定義成一個(gè)消費(fèi)者需要的信號(hào)量(data_sem),在初始化時(shí),它的初始值我們應(yīng)該設(shè)置為0,因?yàn)閯傞_始時(shí)環(huán)形隊(duì)列當(dāng)中沒有數(shù)據(jù)。

當(dāng)生產(chǎn)者線程生產(chǎn)數(shù)據(jù)時(shí),它需要先申請信號(hào)量,即對space_sem進(jìn)行P操作,然后生產(chǎn)數(shù)據(jù),放入到隊(duì)列中。生產(chǎn)完成后,這時(shí),隊(duì)列中就多出了一個(gè)數(shù)據(jù)資源,需要對data_sem進(jìn)行V操作。

當(dāng)消費(fèi)者線程消費(fèi)數(shù)據(jù)時(shí),它也需要先申請信號(hào)量,即對data_sem進(jìn)行P操作,然后消費(fèi)數(shù)據(jù)。消費(fèi)完成后,隊(duì)列中就會(huì)多出一個(gè)空間資源,需要對space_sem進(jìn)行V操作。

2、代碼實(shí)現(xiàn)

對信號(hào)量進(jìn)行封裝:sem.hpp

#pragma once

#include <iostream>
#include <semaphore.h>

using namespace std;

class sem
{
public:
    sem(int sem)
    {
        sem_init(&sem_, 0, sem);
    }

    void p()
    {
        sem_wait(&sem_);
    }

    void v()
    {
        sem_post(&sem_);
    }

    ~sem()
    {
        sem_destroy(&sem_);
    }

private:
    sem_t sem_;
};

1、單生產(chǎn)單消費(fèi)的生產(chǎn)者消費(fèi)者模型

RingQueue.hpp:環(huán)形隊(duì)列的實(shí)現(xiàn):

#include <iostream>
#include <vector>
#include <pthread.h>
#include "sem.hpp"
#include <sys/types.h>
#include <unistd.h>

using namespace std;
#define GVAL 5

template <class T>
class RingQueue
{
public:
    RingQueue(const int num = GVAL)
        : num_(num), rq_(num), space_sem(num), data_sem(0), p_step(0), c_step(0)
    {
    }

    void push(const T &in)
    {
        space_sem.p(); // 申請信號(hào)量
        rq_[p_step++] = in;
        p_step %= num_;
        data_sem.v(); // 釋放信號(hào)量
    }

    void pop(T *out)
    {
        data_sem.p(); // 申請信號(hào)量
        *out = rq_[c_step++];
        c_step %= num_;
        space_sem.v(); // 釋放信號(hào)量
    }

    ~RingQueue()
    {
    }

private:
    vector<T> rq_;
    int num_;      // 大小
    sem space_sem; // 空間資源信號(hào)量
    sem data_sem;  // 數(shù)據(jù)資源信號(hào)量
    int c_step;    // 消費(fèi)者下標(biāo)
    int p_step;    // 生產(chǎn)者下標(biāo)
};

單生產(chǎn)單消費(fèi)的生產(chǎn)者消費(fèi)者模型:

#include <iostream>
#include <pthread.h>
#include "RingQueue.hpp"

using namespace std;

void *consumer(void *arg)
{
    RingQueue<int> *rq = (RingQueue<int> *)arg;
    while(true)
    {
        int x;
        rq->pop(&x);
        cout << "消費(fèi):" << x << endl;
        sleep(1);
    }
}

void *productor(void *arg)
{
    RingQueue<int> *rq = (RingQueue<int> *)arg;
    while(true)
    {
        int x = rand() % 100 + 1;
        rq->push(x);
        cout << "生產(chǎn):" << x << endl;
    }
}

int main()
{
    srand((uint64_t)time(nullptr) ^ getpid() ^ 2321);
    RingQueue<int> *rq = new RingQueue<int>();
    pthread_t c, p;
    pthread_create(&c, nullptr, consumer, (void *)rq);
    pthread_create(&p, nullptr, productor, (void *)rq);

    pthread_join(c, nullptr);
    pthread_join(p, nullptr);

    return 0;
}

運(yùn)行結(jié)果:

Linux之信號(hào)量 | 消費(fèi)者生產(chǎn)者模型的循環(huán)隊(duì)列,Linux,開發(fā)語言,linux

2、多生產(chǎn)多消費(fèi)的生產(chǎn)者消費(fèi)者模型

我們只要保證,最終進(jìn)入臨界區(qū)的是一個(gè)生產(chǎn)者,一個(gè)消費(fèi)就行,即生產(chǎn)者和生產(chǎn)者之間是互斥的,消費(fèi)者和消費(fèi)者之間是互斥的。所以我們需要提供兩把鎖。

RingQueue.hpp:

#include <iostream>
#include <vector>
#include <pthread.h>
#include "sem.hpp"
#include <sys/types.h>
#include <unistd.h>

using namespace std;
#define GVAL 5

template <class T>
class RingQueue
{
public:
    RingQueue(const int num = GVAL)
        : num_(num), rq_(num), space_sem(num), data_sem(0), p_step(0), c_step(0)
    {
        pthread_mutex_init(&clock, nullptr);
        pthread_mutex_init(&plock, nullptr);
    }

    void push(const T &in)
    {
        space_sem.p(); // 申請信號(hào)量
        pthread_mutex_lock(&plock);
        rq_[p_step++] = in;
        p_step %= num_;
        pthread_mutex_unlock(&plock);
        data_sem.v(); // 釋放信號(hào)量
    }

    void pop(T *out)
    {
        data_sem.p(); // 申請信號(hào)量
        pthread_mutex_lock(&clock);
        *out = rq_[c_step++];
        c_step %= num_;
        pthread_mutex_unlock(&clock);
        space_sem.v(); // 釋放信號(hào)量
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }

private:
    vector<T> rq_;
    int num_;      // 大小
    sem space_sem; // 空間資源信號(hào)量
    sem data_sem;  // 數(shù)據(jù)資源信號(hào)量
    int c_step;    // 消費(fèi)者下標(biāo)
    int p_step;    // 生產(chǎn)者下標(biāo)
    pthread_mutex_t plock;
    pthread_mutex_t clock;
};
#include <iostream>
#include <pthread.h>
#include "RingQueue.hpp"

using namespace std;

void *consumer(void *arg)
{
    RingQueue<int> *rq = (RingQueue<int> *)arg;
    while (true)
    {
        int x;
        rq->pop(&x);
        cout << "消費(fèi):" << x << " " << pthread_self() << endl;
        sleep(1);
    }
}

void *productor(void *arg)
{
    RingQueue<int> *rq = (RingQueue<int> *)arg;
    while (true)
    {
        int x = rand() % 100 + 1;
        rq->push(x);
        cout << "生產(chǎn):" << x << " " << pthread_self() << endl;
    }
}

int main()
{
    srand((uint64_t)time(nullptr) ^ getpid() ^ 2321);
    RingQueue<int> *rq = new RingQueue<int>();
    pthread_t c[2], p[3];
    for (int i = 0; i < 2; i++)
        pthread_create(c + i, nullptr, consumer, (void *)rq);
    for (int i = 0; i < 3; i++)
        pthread_create(p + i, nullptr, productor, (void *)rq);

    for (int i = 0; i < 2; i++)
        pthread_join(c[i], nullptr);
    for (int i = 0; i < 3; i++)
        pthread_join(p[i], nullptr);

    return 0;
}

運(yùn)行結(jié)果:

Linux之信號(hào)量 | 消費(fèi)者生產(chǎn)者模型的循環(huán)隊(duì)列,Linux,開發(fā)語言,linux文章來源地址http://www.zghlxwxcb.cn/news/detail-854347.html

到了這里,關(guān)于Linux之信號(hào)量 | 消費(fèi)者生產(chǎn)者模型的循環(huán)隊(duì)列的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Linux學(xué)習(xí)】多線程——信號(hào)量 | 基于環(huán)形隊(duì)列的生產(chǎn)者消費(fèi)者模型 | 自旋鎖 | 讀寫鎖

    【Linux學(xué)習(xí)】多線程——信號(hào)量 | 基于環(huán)形隊(duì)列的生產(chǎn)者消費(fèi)者模型 | 自旋鎖 | 讀寫鎖

    ??作者:一只大喵咪1201 ??專欄:《Linux學(xué)習(xí)》 ??格言: 你只管努力,剩下的交給時(shí)間! 之前在學(xué)習(xí)進(jìn)程間通信的時(shí)候,本喵簡單的介紹過一下信號(hào)量,今天在這里進(jìn)行詳細(xì)的介紹。 這是之前寫的基于阻塞隊(duì)列的生產(chǎn)者消費(fèi)者模型中向阻塞隊(duì)列中push任務(wù)的代碼。 上面代碼

    2024年02月07日
    瀏覽(20)
  • 第三章 Linux多線程開發(fā) 線程取消 屬性 同步 互斥鎖 死鎖 讀寫鎖 生產(chǎn)者消費(fèi)者 信號(hào)量
  • 12.3用信號(hào)量進(jìn)行線程同步——生產(chǎn)者與消費(fèi)者問題

    1.shell程序設(shè)計(jì) 2.內(nèi)存管理 3.鏈接庫 4.文件操作

    2024年02月04日
    瀏覽(26)
  • 【設(shè)計(jì)模式】C語言使用共享內(nèi)存和信號(hào)量,完美實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者模式

    生產(chǎn)者和消費(fèi)者模式適用于生產(chǎn)者和消費(fèi)者之間存在數(shù)據(jù)交換的場景。在這種模式中,生產(chǎn)者負(fù)責(zé)生產(chǎn)數(shù)據(jù)并將其放入緩沖區(qū),而消費(fèi)者負(fù)責(zé)從緩沖區(qū)中取出數(shù)據(jù)并進(jìn)行處理。這種模式的優(yōu)點(diǎn)是可以實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者之間的解耦,使得它們可以獨(dú)立地進(jìn)行操作,從而提高了

    2024年02月03日
    瀏覽(19)
  • QT QThread +信號(hào)量 實(shí)現(xiàn)生成者和消費(fèi)者

    //本文詳細(xì)描述QT 中QThread +信號(hào)量 實(shí)現(xiàn)生成者和消費(fèi)者。 //調(diào)試通過。 //這個(gè)例子演示了怎樣使用QSemaphore 信號(hào)量來保護(hù)對生成者線程和消費(fèi)者線程共享的環(huán)形緩沖 //區(qū)的訪問。 //生成者向緩沖區(qū)中寫入數(shù)據(jù),直到達(dá)到緩沖區(qū)的終點(diǎn),這時(shí)它會(huì)從起點(diǎn)重新開始,覆蓋已經(jīng)存在

    2024年04月14日
    瀏覽(17)
  • 線程同步、生產(chǎn)者消費(fèi)模型和POSIX信號(hào)量

    線程同步、生產(chǎn)者消費(fèi)模型和POSIX信號(hào)量

    gitee倉庫: 1.阻塞隊(duì)列代碼:https://gitee.com/WangZihao64/linux/tree/master/BlockQueue 2.環(huán)形隊(duì)列代碼:https://gitee.com/WangZihao64/linux/tree/master/ringqueue 概念 : 利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括兩個(gè)動(dòng)作:一個(gè)線程等待\\\"條件變量的條件成立\\\"而掛起;另一個(gè)線程使“

    2024年02月03日
    瀏覽(23)
  • linux:生產(chǎn)者消費(fèi)者模型

    linux:生產(chǎn)者消費(fèi)者模型

    個(gè)人主頁 : 個(gè)人主頁 個(gè)人專欄 : 《數(shù)據(jù)結(jié)構(gòu)》 《C語言》《C++》《Linux》 本文是對于生產(chǎn)者消費(fèi)者模型的知識(shí)總結(jié) 生產(chǎn)者消費(fèi)者模型就是通過一個(gè)容器來解決生產(chǎn)者消費(fèi)者的強(qiáng)耦合問題。生產(chǎn)者和消費(fèi)者彼此之間不直接通訊,而是通過之間的容器來進(jìn)行通訊,所以生產(chǎn)者

    2024年04月15日
    瀏覽(19)
  • Linux——生產(chǎn)者消費(fèi)者模型

    Linux——生產(chǎn)者消費(fèi)者模型

    目錄 一.為何要使用生產(chǎn)者消費(fèi)者模型 ?二.生產(chǎn)者消費(fèi)者模型優(yōu)點(diǎn) ?三.基于BlockingQueue的生產(chǎn)者消費(fèi)者模型 1.BlockingQueue——阻塞隊(duì)列 2.實(shí)現(xiàn)代碼 ?四.POSIX信號(hào)量 五.基于環(huán)形隊(duì)列的生產(chǎn)消費(fèi)模型 生產(chǎn)者消費(fèi)者模式就是通過一個(gè)容器來解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問題。生產(chǎn)者

    2024年02月08日
    瀏覽(22)
  • 【linux】POSIX信號(hào)量+基于環(huán)形隊(duì)列的生產(chǎn)消費(fèi)模型

    【linux】POSIX信號(hào)量+基于環(huán)形隊(duì)列的生產(chǎn)消費(fèi)模型

    喜歡的點(diǎn)贊,收藏,關(guān)注一下把! 上篇文章最后我們基于BlockQueue生產(chǎn)者消費(fèi)者模型寫了代碼,測試什么的都通過了。最后我們說代碼還有一些不足的地方,由這些不足從而引入了我們接下來要學(xué)的信號(hào)量! 我們在看一看不足的地方 1.一個(gè)線程,在操作臨界資源的時(shí)候,必須

    2024年02月01日
    瀏覽(24)
  • 【Linux】深入理解生產(chǎn)者消費(fèi)者模型

    【Linux】深入理解生產(chǎn)者消費(fèi)者模型

    生產(chǎn)者 - 消費(fèi)者模型 Producer-consumer problem 是一個(gè)非常經(jīng)典的多線程并發(fā)協(xié)作的模型,在分布式系統(tǒng)里非常常見。 在多線程開發(fā)中,如果生產(chǎn)者生產(chǎn)數(shù)據(jù)的速度很快,而消費(fèi)者消費(fèi)數(shù)據(jù)的速度很慢,那么生產(chǎn)者就必須等待消費(fèi)者消費(fèi)完了數(shù)據(jù)才能夠繼續(xù)生產(chǎn)數(shù)據(jù),同理如果消費(fèi)

    2024年02月06日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包