C語(yǔ)言通過(guò)案例講解并發(fā)編程模型
下面代碼、思路等來(lái)源于b站郭郭 和CSAPP樣例,同時(shí)希望大家好好讀一下CSAPP的內(nèi)容,真的講的很好
1、按照指定的順序輸出
我們執(zhí)行兩個(gè)線程:foo1 和foo2
foo1:打印step1, step3
foo2:打印step2
請(qǐng)用并發(fā)使得按照1 2 3 的順序輸出
答:首先兩個(gè)線程執(zhí)行順序不可預(yù)判,我們必須保證打印step2之前step1就打印好了,因此需要阻塞一下step2,實(shí)現(xiàn)的方式是初始化sem為0,只有打印完step1后(然后進(jìn)行解鎖,V操作)step2才能執(zhí)行
同理,只有打印完step2后才解開(kāi)阻塞step3的鎖,具體看代碼實(shí)現(xiàn)就明白了
#include "csapp.c"
sem_t step1_done, step2_done;
void* foo1() {
printf("test1 is done\n");
V(&step1_done); //step1執(zhí)行完畢了,那么foo2的阻塞就會(huì)被解開(kāi)
P(&step2_done); //測(cè)試是否step2執(zhí)行完畢,
printf("test3 is done\n");
return NULL;
}
void* foo2() {
P(&step1_done);
printf("test2 is done\n");
V(&step2_done); //step2執(zhí)行完畢,解開(kāi)打印step的鎖
return NULL;
}
int main()
{
pthread_t tid1, tid2;
Sem_init(&step1_done, 0, 0); //第二個(gè)參數(shù)為0:在線程之間進(jìn)行, 第三個(gè)參數(shù)初始化都為零
Sem_init(&step2_done, 0, 0);
Pthread_create(&tid1, NULL, foo1, NULL);
Pthread_create(&tid2, NULL, foo2, NULL);
//保證線程執(zhí)行完畢之后主線程才退出,否則線程都執(zhí)行不了了
Pthread_join(tid1, NULL);
Pthread_join(tid2, NULL);
exit(0);
}
2、生產(chǎn)者消費(fèi)者模型
主要的就是在生產(chǎn)和消費(fèi)函數(shù)中對(duì)于信號(hào)量的處理
錯(cuò)誤實(shí)例:
void sbuf_insert(subf_t* sp, int item) {
sem_wait(&sp->mutex);
sem_wait(&sp->slots);
//將項(xiàng)目放進(jìn)buf中
sp->buf[(++sp->rear) % (sp->n)] = item;
sem_post(&sp->items);
sem_post(&sp->mutex);
}
void sbuf_remove(sbuf_t* sp) {
sem_wait(&sp->mutex);
sem_wait(&sp->items);
//do works
sem_post(&sp->slots);
sem_post(&sp->mutex);
}
如果我們?cè)谔幚淼臅r(shí)候先拿到 互斥鎖,可能就會(huì)引起死鎖
假設(shè)現(xiàn)在buf是滿的,生產(chǎn)者拿到了互斥鎖,但是自己因?yàn)闆](méi)有空閑被 block…
此時(shí)消費(fèi)者同樣因?yàn)槟貌坏交コ怄i而被 block…
其他的生產(chǎn)者同樣也是沒(méi)有 互斥鎖被block…
解決方法:
比較簡(jiǎn)單,調(diào)換一下順序就好了。相當(dāng)于我們生產(chǎn)者、消費(fèi)者在進(jìn)行的時(shí)候 明確我到底要操控哪個(gè)格子 然后再拿mutex??
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
typedef struct sbuf{
int *buf; /*堆上開(kāi)辟的內(nèi)存,用于存儲(chǔ)*/
int n; /*cap of the buf*/
int front; //第一個(gè)item
int rear; //最后一個(gè)item
sem_t mutex; //獲取臨界區(qū)的鎖
sem_t slots; //空槽數(shù)目
sem_t items; //已經(jīng)生產(chǎn)了的數(shù)目
}subf_t;
void sbuf_init(subf_t* sp, int n) {
sp->n = n;
sp->buf = static_cast<int *>(calloc(n, sizeof(int)));
sp->front = 0;
sp->rear = 0;
sem_init(&sp->mutex, 0, 1);
sem_init(&sp->slots, 0, n);
sem_init(&sp->items, 0, 0);
}
void sbuf_deinit(subf_t*sp) {
free(sp->buf);
}
void sbuf_insert(subf_t* sp, int item) {
//首先應(yīng)該對(duì)信號(hào)量slots判斷,你生產(chǎn)者看中
sem_wait(&sp->slots);
sem_wait(&sp->mutex);
//將項(xiàng)目放進(jìn)buf中
sp->buf[(++sp->rear) % (sp->n)] = item;
//CSAPP中提到,解鎖的順序一般是和加鎖的順序是相反的
sem_post(&sp->mutex);
sem_post(&sp->items);
}
int sbuf_remove(subf_t* sp) {
int item;
sem_wait(&sp->items); //我看上哪個(gè)格子的產(chǎn)品了
sem_wait(&sp->mutex);
item = sp->buf[(++sp->front) % (sp->n)];
sem_post(&sp->mutex);
sem_post(&sp->slots);
return item;
}3、讀寫(xiě)鎖
第一類(lèi)讀者、寫(xiě)者問(wèn)題(讀者優(yōu)先)
- 不會(huì)讓讀者進(jìn)行等待的,除非現(xiàn)在的權(quán)限是寫(xiě)者的
- 也就是說(shuō)讀者不會(huì)因?yàn)橛幸粋€(gè)寫(xiě)者在等待
實(shí)現(xiàn):
信號(hào)量:w維護(hù)著對(duì)于critical section的訪問(wèn), mutex維護(hù)這對(duì)于共享變量readcnt(當(dāng)前在臨界區(qū)的讀者的數(shù)量)的訪問(wèn)
每當(dāng)寫(xiě)者進(jìn)入了臨界區(qū),就對(duì)w進(jìn)行加鎖??,離開(kāi)就解鎖。保證了任意時(shí)刻臨界區(qū)最多只能有一個(gè)寫(xiě)者
只有第一個(gè)讀者進(jìn)入的時(shí)候?qū)加鎖,最后一個(gè)才釋放,那么只要還有一個(gè)讀者在,其他任意的讀者就能夠無(wú)障礙的進(jìn)入,同樣會(huì)導(dǎo)致 寫(xiě)者饑餓
int readcnt = 0;
sem_t ,mutex = 1, w = 1;
void reader() {
while (1) {
P(&mutex);
readcnt++;
if (readcnt == 1) //第一個(gè)進(jìn)入的讀者
P(&w); //上鎖,寫(xiě)者不能寫(xiě)了
V(&mutex); //解開(kāi)對(duì)于readcnt的保護(hù)鎖
/*
臨界區(qū)的工作
*/
P(&mutex);
readcnt--;
if (readcnt == 0)
V(&w); //最后一個(gè)讀者了, 解開(kāi)阻塞寫(xiě)者的鎖
V(&mutex); //解開(kāi)對(duì)readcnt的保護(hù)鎖
}
}
void writer() {
while (1) {
P(&w);
/*
臨界區(qū)工作
*/
V(&w);
}
}
到此這篇關(guān)于C語(yǔ)言通過(guò)案例講解并發(fā)編程模型的文章就介紹到這了,更多相關(guān)C語(yǔ)言 并發(fā)編程內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中引用(&)的用法與應(yīng)用實(shí)例分析
引用是C++引入的新語(yǔ)言特性,是C++常用的一個(gè)重要內(nèi)容之一,正確、靈活地使用引用,可以使程序簡(jiǎn)潔、高效。故在本篇中我將對(duì)引用進(jìn)行詳細(xì)討論,希望對(duì)大家更好地理解和使用引用起到拋磚引玉的作用2013-09-09
C語(yǔ)言文字藝術(shù)之?dāng)?shù)據(jù)輸入輸出
這篇文章主要介紹了C語(yǔ)言文字藝術(shù)之?dāng)?shù)據(jù)輸入輸出,C語(yǔ)言的語(yǔ)句用來(lái)向計(jì)算機(jī)系統(tǒng)發(fā)出操作指令。一條語(yǔ)句編寫(xiě)完成經(jīng)過(guò)編譯后產(chǎn)生若干條機(jī)器指2022-07-07
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中串的模式匹配
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)中串的模式匹配的相關(guān)資料,需要的朋友可以參考下2017-05-05
C++實(shí)現(xiàn)并優(yōu)化異常系統(tǒng)
異常處理是C++的一項(xiàng)語(yǔ)言機(jī)制,用于在程序中處理異常事件,下面這篇文章主要給大家介紹了關(guān)于C++中異常的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
C語(yǔ)言 選擇排序算法詳解及實(shí)現(xiàn)代碼
本文主要介紹C語(yǔ)言 選擇排序算法,這里對(duì)排序算法做了詳細(xì)說(shuō)明,并附代碼示例,有需要的小伙伴可以參考下2016-08-08
C語(yǔ)言代碼實(shí)現(xiàn)簡(jiǎn)易掃雷
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言代碼實(shí)現(xiàn)簡(jiǎn)易掃雷,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01
OpenCV reshape函數(shù)實(shí)現(xiàn)矩陣元素序列化
reshape函數(shù)是OpenCV中一個(gè)很有用的函數(shù),不僅可以改變矩陣的通道數(shù),還可以對(duì)矩陣元素進(jìn)行序列化。本文將主要介紹如何通過(guò)reshape實(shí)現(xiàn)矩陣元素序列化,需要的小伙伴可以參考一下2021-12-12
C/C++語(yǔ)言中結(jié)構(gòu)體的內(nèi)存分配小例子
當(dāng)未用 #pragma 指令指定編譯器的對(duì)齊位數(shù)時(shí),結(jié)構(gòu)體按最長(zhǎng)寬度的數(shù)據(jù)成員的寬度對(duì)齊;當(dāng)使用了 #pragma 指令指定編譯器的對(duì)齊位數(shù)時(shí),結(jié)構(gòu)體按最長(zhǎng)寬度的數(shù)據(jù)成員的寬度和 #pragma 指令指定的位數(shù)中的較小值對(duì)齊2013-10-10

