溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型

發(fā)布時間:2020-06-27 22:33:06 來源:網(wǎng)絡 閱讀:849 作者:程紅玲OOO 欄目:編程語言

system v和posix版本信號量的接口函數(shù)

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型


本篇介紹POSIX版本的Semaphore(信號量)


Mutex變量是非0即1的,可看作一種資源的可用數(shù)量,初始化時Mutex是1,表示有一個可用資源,加鎖時獲得該資源,將Mutex減到0,表示不再有可用資源,解鎖時釋放該資源,將Mutex重新加到1,表示又有了一個可用資源。


信號量(Semaphore)和Mutex類似,表示可用資源的數(shù)量,和Mutex不同的是這個數(shù)量可以大于1。如果信號量描述的資源數(shù)目是1時,此時的信號量和互斥鎖相同!


POSIX semaphore庫函數(shù),這種信號量不僅可用于同一進程的線程間同步,也可用于不同進程間的同步。


有了互斥量和條件變量還提供信號量的原因 是:信號量的主要目的是提供一種進程間同步的方式。這種同步的進程可以共享也可以不共享內存區(qū)。雖然信號量的意圖在于進程間的同步,互斥量和條件變量的意圖在于線程間同步,但信號量也可用于線程間同步,互斥量和條件變量也可通過共享內存區(qū)進行進程間同步。 但應該根據(jù)具體應用考慮到效率和易用性進行具體的選擇。



POSIX版本信號量分為有名信號量無名信號量

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型

有名信號量函數(shù):

sem_open 用于創(chuàng)建或打開一個信號量,信號量是通過 name 參數(shù)即信號量的名字來進行標識的。

sem_close 用于關閉打開的信號量。當一個進程終止時,內核對其上仍然打開的所有有名信號量自動執(zhí)行這個操作。

 POSIX 有名信號量是隨內核持續(xù)的。

sem_unlink 用于將有名信號量立刻從系統(tǒng)中刪除,但信號量的銷毀是在所有進程都關閉信號量的時候。

無名信號量有關函數(shù):


POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型


以下代碼是用無名信號量實現(xiàn)的生產者消費者模型


生產者消費者模型:

代碼說明:

1.push()和pop()的數(shù)據(jù)(datatype)本篇用的是基本類型,如果是自定義類型的話,需要實現(xiàn)賦值運算符的重載

2.數(shù)組實際上是線性的,內存中并沒有環(huán)形數(shù)組,我們定義了一個固定大小的數(shù)組,當數(shù)組的最后一個元素也被填上數(shù)據(jù)時,檢查數(shù)組的第一個元素(下標為0的元素)是否已經被消費者讀過,如果已經讀過,那么生產者就可以繼續(xù)放數(shù)據(jù),當數(shù)組滿時(即數(shù)組中的元素一個也沒有被消費者讀),生產者會等待。

3.sem_init()初始化兩個信號量sem_p(控制生產者)和sem_c(控制消費者),pshared為0時,表示信號量用于同一進程的線程間同步

 sem_destroy()使兩個信號量回到初始化前的狀態(tài)

 sem_wait() 可以獲得資源,相當于P操作,把給定信號量減一

 sem_post() 可以釋放資源,相當于V操作,進行加一操作

 當信號量的值為0時,sem_wait()會將進程掛起等待,sem_trywait()不會將進程掛起

4.多生產者和多消費者模型則需要加鎖,其實加用兩把不同的鎖實現(xiàn)效率更高,可以使線程并發(fā)執(zhí)行,而我在下面代碼中指使用了一把鎖,在下面代碼中我把它標記了出來


代碼實現(xiàn):

ring.cpp

#include <iostream>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
using namespace std;

#define SEM_PRO 20
#define SEM_CON 0
#define SIZE SEM_PRO

typedef int datatype; 

datatype ring[SIZE];//數(shù)組的定義
datatype pro,con;

sem_t sem_p;//product
sem_t sem_c;//consumer


void init_ring(datatype (*ring)[SIZE])
{
    pro=0;
    con=0;
 }

datatype& push(datatype &data,int index)
{
    ring[pro++]=data;
    datatype tmp=ring[pro-1];
    pro%=SIZE;
    return tmp;
}

datatype& pop(int index)
{
    con++;
    datatype tmp=ring[con-1];
    con%=SIZE;
    return tmp;
}

void* product(void* arg)
{
    while(1){
        datatype data=rand()%50;
        sem_wait(&sem_p);
        datatype val=push(data,pro);
        cout<<"product done...,val is:"<<val<<endl;
        sem_post(&sem_c);
        sleep(1);
    }
}

void* consumer(void* arg)
{
    while(1){
        sem_wait(&sem_c);
        datatype val=pop(con);
        cout<<"consumer done...,val is:"<<val<<endl;
        sem_post(&sem_p);
        sleep(8);
    }
}

int main()
{
    init_ring(&ring);

    sem_init(&sem_p,0,SEM_PRO);
    sem_init(&sem_c,0,0);

    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,product,NULL);
    pthread_create(&tid2,NULL,consumer,NULL);

    sem_destroy(&sem_p);
    sem_destroy(&sem_c);

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

    return 0;
}

Makefile

ring:ring.cpp
    g++ -o $@ $^ -lpthread

.PHONY:clean
clean:
    rm -f ring


下面兩次運行生產者和消費者的速度有所變化,導致運行結果不同

第一次運行結果:

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型

第二次運行結果:

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型


生產者消費者模型:

#include <iostream>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
using namespace std;

#define SEM_PRO 20
#define SEM_CON 0
#define SIZE SEM_PRO

typedef int datatype;

datatype ring[SIZE];
datatype pro,con;

sem_t sem_p;//product
sem_t sem_c;//consumer

void init_ring(datatype (*ring)[SIZE])
{
    pro=0;
    con=0;
}

datatype& push(datatype &data,int index)
{
    ring[pro++]=data;
    datatype tmp=ring[pro-1];
    pro%=SIZE;
    return tmp;
}

datatype& pop(int index)
{
    con++;
    datatype tmp=ring[con-1];
    con%=SIZE;
    return tmp;
}

void* product(void* arg)
{
     while(1){
        int value;
        datatype data=rand()%50;
        sem_wait(&sem_p);//申請資源,進行減一操作
        pthread_mutex_lock(&lock);
        datatype val=push(data,pro);//往buf里push數(shù)據(jù)
        sem_getvalue(&sem_p,&value);//得到此時信號量sem_p的值,即還有幾個空格可>以使用
        pthread_mutex_unlock(&lock);
        cout<<"product"<<(int)arg<<" done...,val is:"<<val<<endl;
        cout<<"sem_p is:"<<value<<",";
        pthread_mutex_lock(&lock);//**********************************應加不同的鎖
        sem_post(&sem_c);//釋放資源
        sem_getvalue(&sem_c,&value);//得到此時信號量sem_c的值,即有多少數(shù)據(jù)可以>取
        pthread_mutex_unlock(&lock);
        cout<<"sem_c is:"<<value<<endl;

        sleep(5);
    }
}

void* consumer(void* arg)
{
     while(1){
        int value;
        sem_wait(&sem_c);
        pthread_mutex_lock(&lock);
        datatype val=pop(con);
        sem_getvalue(&sem_c,&value);
        pthread_mutex_unlock(&lock);
        cout<<"consumer"<<(int)arg<<" done...,val is:"<<val<<endl;
        cout<<"sem_c is:"<<value<<",";
        pthread_mutex_lock(&lock);//**********************************應加不同的鎖
        sem_post(&sem_p);
        sem_getvalue(&sem_p,&value);
        pthread_mutex_unlock(&lock);
        cout<<"sem_p is:"<<value<<endl;
        sleep(1);
    }
}

int main()
{
    init_ring(&ring);

    sem_init(&sem_p,0,SEM_PRO);
    sem_init(&sem_c,0,0);

    pthread_t tid1,tid2,tid3;
    pthread_create(&tid1,NULL,product,(void*)1);
    pthread_create(&tid2,NULL,product,(void*)2);
    pthread_create(&tid3,NULL,product,(void*)3);

    pthread_t tid4,tid5;
    pthread_create(&tid4,NULL,consumer,(void*)4);
    pthread_create(&tid5,NULL,consumer,(void*)5);

    sem_destroy(&sem_p);
    sem_destroy(&sem_c);

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    pthread_join(tid3,NULL);
    pthread_join(tid4,NULL);
    pthread_join(tid5,NULL);

    return 0;
}

運行結果:

POSIX信號量——環(huán)形buf實現(xiàn)生產者消費者模型


很多時候信號量和互斥量,條件變量三者都可以再某種應用中使用,那這三者的差異有哪些呢,下面列出了這三者之間的差異 :

  • 互斥量必須由給它上鎖的線程解鎖。而信號量不需要由等待它的線程進行掛出,可以在其他進程進行掛出操作。

  • 互斥量要么被鎖住,要么是解開狀態(tài),只有這兩種狀態(tài)。而信號量的值可以支持多個進程成功進行 wait 操作。

  • 信號量的掛出操作總是被記住,因為信號量有一個計數(shù)值,掛出操作總會將該計數(shù)值加 1 ,然而當向條件變量發(fā)送一個信號時,如果沒有線程等待在條件變量,那么該信號會丟失。



向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經查實,將立刻刪除涉嫌侵權內容。

AI