網站首頁 編程語言 正文
下面代碼、思路等來源于b站郭郭 和CSAPP樣例,同時希望大家好好讀一下CSAPP的內容,真的講的很好
1、按照指定的順序輸出
我們執行兩個線程:foo1 和foo2
foo1:打印step1, step3
foo2:打印step2
請用并發使得按照1 2 3 的順序輸出
答:首先兩個線程執行順序不可預判,我們必須保證打印step2之前step1就打印好了,因此需要阻塞一下step2,實現的方式是初始化sem為0,只有打印完step1后(然后進行解鎖,V操作)step2才能執行
同理,只有打印完step2后才解開阻塞step3的鎖,具體看代碼實現就明白了
#include "csapp.c"
sem_t step1_done, step2_done;
void* foo1() {
printf("test1 is done\n");
V(&step1_done); //step1執行完畢了,那么foo2的阻塞就會被解開
P(&step2_done); //測試是否step2執行完畢,
printf("test3 is done\n");
return NULL;
}
void* foo2() {
P(&step1_done);
printf("test2 is done\n");
V(&step2_done); //step2執行完畢,解開打印step的鎖
return NULL;
}
int main()
{
pthread_t tid1, tid2;
Sem_init(&step1_done, 0, 0); //第二個參數為0:在線程之間進行, 第三個參數初始化都為零
Sem_init(&step2_done, 0, 0);
Pthread_create(&tid1, NULL, foo1, NULL);
Pthread_create(&tid2, NULL, foo2, NULL);
//保證線程執行完畢之后主線程才退出,否則線程都執行不了了
Pthread_join(tid1, NULL);
Pthread_join(tid2, NULL);
exit(0);
}
2、生產者消費者模型
主要的就是在生產和消費函數中對于信號量的處理
錯誤實例:
void sbuf_insert(subf_t* sp, int item) {
sem_wait(&sp->mutex);
sem_wait(&sp->slots);
//將項目放進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);
}
如果我們在處理的時候先拿到 互斥鎖,可能就會引起死鎖
假設現在buf是滿的,生產者拿到了互斥鎖,但是自己因為沒有空閑被 block…
此時消費者同樣因為拿不到互斥鎖而被 block…
其他的生產者同樣也是沒有 互斥鎖被block…
解決方法:
比較簡單,調換一下順序就好了。相當于我們生產者、消費者在進行的時候 明確我到底要操控哪個格子 然后再拿mutex??
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
typedef struct sbuf{
int *buf; /*堆上開辟的內存,用于存儲*/
int n; /*cap of the buf*/
int front; //第一個item
int rear; //最后一個item
sem_t mutex; //獲取臨界區的鎖
sem_t slots; //空槽數目
sem_t items; //已經生產了的數目
}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) {
//首先應該對信號量slots判斷,你生產者看中
sem_wait(&sp->slots);
sem_wait(&sp->mutex);
//將項目放進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); //我看上哪個格子的產品了
sem_wait(&sp->mutex);
item = sp->buf[(++sp->front) % (sp->n)];
sem_post(&sp->mutex);
sem_post(&sp->slots);
return item;
}
3、讀寫鎖
第一類讀者、寫者問題(讀者優先)
- 不會讓讀者進行等待的,除非現在的權限是寫者的
- 也就是說讀者不會因為有一個寫者在等待
實現:
信號量:w維護著對于critical section的訪問, mutex維護這對于共享變量readcnt(當前在臨界區的讀者的數量)的訪問
每當寫者進入了臨界區,就對w進行加鎖??,離開就解鎖。保證了任意時刻臨界區最多只能有一個寫者
只有第一個讀者進入的時候對W加鎖,最后一個才釋放,那么只要還有一個讀者在,其他任意的讀者就能夠無障礙的進入,同樣會導致 寫者饑餓
int readcnt = 0;
sem_t ,mutex = 1, w = 1;
void reader() {
while (1) {
P(&mutex);
readcnt++;
if (readcnt == 1) //第一個進入的讀者
P(&w); //上鎖,寫者不能寫了
V(&mutex); //解開對于readcnt的保護鎖
/*
臨界區的工作
*/
P(&mutex);
readcnt--;
if (readcnt == 0)
V(&w); //最后一個讀者了, 解開阻塞寫者的鎖
V(&mutex); //解開對readcnt的保護鎖
}
}
void writer() {
while (1) {
P(&w);
/*
臨界區工作
*/
V(&w);
}
}
原文鏈接:https://blog.csdn.net/qq_52245648/article/details/124176984
相關推薦
- 2022-10-13 解析批處理命令call和start_DOS/BAT
- 2023-02-07 Pytorch中torch.cat()函數的使用及說明_python
- 2022-04-22 react useState ,useEfffect設置元素高度,注意加單位
- 2023-03-01 shell?wait等待命令的具體使用_linux shell
- 2024-03-19 maven本地倉庫有包,導致could not find artifact
- 2022-04-09 使用docker-compose一鍵部署開源博客wordpress
- 2022-03-14 ffmpeg開發讀取目錄列表
- 2023-04-24 Python中__init__的用法和理解示例詳解_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支