Linux中多线程使用信号量(信号灯),和sem_wait()函数使用
文章目錄
- 編程環(huán)境:
- 信號量(信號燈):
- 使用步驟:
- “生產(chǎn)者-消費者”例子:
- 理論模型:
- 代碼分析:
- 代碼實現(xiàn):
- 運行結果:
- Mac 下對 sem_init()/sem_destory() 不支持:
- 下載地址:
- 系列地址:
簡 述: 上一篇中講解了“條件變量 + 互斥量”的組合使用,演示了 “生產(chǎn)者-消費者”模型。本篇講解 互斥量的升級版:信號量(信號燈) 的理解和使用。互斥量與信號量的關系,可以簡單理解為 c 和 c++ 的關系。信號量的使用的步驟,也是和前面的互斥量很像,不過這次的頭文件改為了 #include <semaphore.h>:
- sem_t sem; //定義變量
- sem_wait(); //加鎖
- …其他代碼
- sem_post(); //解鎖
- sem_destroy(); //銷毀
說明:
本例子是在 Linux 下面運行成功的,編譯時候,時候需要加參數(shù) -pthread 。
若是想要在 Mac 運行改程序,需要改寫替換部分函數(shù)(mac 不支持其中的部分函數(shù))
編程環(huán)境:
💻: uos20 📎 gcc/g++ 8.3 📎 gdb8.0
💻: MacOS 10.14 📎 gcc/g++ 9.2 📎 gdb8.3
信號量(信號燈):
簡單理解為里面具有多個互斥量的集合。是加強版的互斥鎖。
其他:
sem_t sem; int sem_init(sem_t *sem, int pshared, unsigned int value);之間的一些解釋:
sem 變量和 函數(shù) sem_init 中的 sem 參數(shù)是同一個;在函數(shù)里面,第一個參數(shù) sem 實際是和第三個參數(shù) value 關聯(lián)的;表面上對 sem 進行修改,實際上是修改關聯(lián)的 value 的值,對其進行 ++ 或 – 操作。(嗯嗯,原理就這么理解就行)。
使用步驟:
sem_t sem;
初始化信號量
int sem_init(sem_t *sem, int pshared, unsigned int value);- 參數(shù):
- pshared:
- 0 - 線程同步
- 1 - 進程同步
- value:
- 最多有幾個線程操作共享數(shù)據(jù)
- pshared:
加鎖:
//調(diào)用一次相當于對 sem 做了一次 -- 操作 int sem_wait(sem_t *sem); //加鎖; => 如果 sem 值為 0,線程會阻塞int sem_trywait(sem_t *sem); //嘗試加鎖; => sem == 0,加鎖失敗,不阻塞,直接返回int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); //限時嘗試加鎖解鎖:
int sem_post(sem_t *sem); //相當于對于 sem 做了 ++ 操作銷毀信號量
int sem_destroy(sem_t *sem);“生產(chǎn)者-消費者”例子:
將上一篇的例子改一改,直接使用信號量來寫這個例子“生產(chǎn)者-消費者”。本篇文章例子如下:
理論模型:
代碼分析:
多看一下理論模型的那個偽代碼的流程圖,多體會揣摩其中的箭頭的流向,且一開始這設置為消費者為阻塞,當生產(chǎn)者生產(chǎn)之后,為其解鎖。
代碼實現(xiàn):
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h>sem_t semProducer; sem_t semCustomer;typedef struct node //節(jié)點結構 {int data;struct node* next; } Node;Node* g_head = nullptr; //永遠指向鏈表頭部的指針void* funProducer(void* arg); //生產(chǎn)者--添加一個頭結點 void* funCustomer(void* arg); //消費者--刪除一個頭結點int main(int argc, char *argv[]) {pthread_t p1;pthread_t p2;sem_init(&semProducer, 0, 4); //初始化生產(chǎn)者線程信號量, (賦予 4 個,對比下一行,讓生產(chǎn)者先運行)sem_init(&semCustomer, 0, 0); //初始化消費者線程信號量, (賦予 0 個, 一開始就讓消費者處于阻塞狀態(tài))pthread_create(&p1, nullptr, funProducer, nullptr); //創(chuàng)建生產(chǎn)者線程pthread_create(&p2, nullptr, funCustomer, nullptr); //創(chuàng)建消費者線程pthread_join(p1, nullptr); //阻塞回收子線程pthread_join(p2, nullptr);sem_destroy(&semProducer); //銷毀生產(chǎn)者信號量sem_destroy(&semCustomer); //銷毀消費者信號量return 0; }void* funProducer(void* arg) {while (true) {sem_wait(&semProducer); //semProducer--, == 0, 則阻塞Node* pNew = new Node();pNew->data = rand() % 1000; pNew->next = g_head;g_head = pNew;printf("-----funProducer(生產(chǎn)者): %lu, %d\n", pthread_self(), pNew->data);sem_post(&semCustomer); // semCustomer++sleep(rand() % 3); //隨機休息 0~2 s}return nullptr; }void* funCustomer(void* arg) {while (true) {sem_wait(&semCustomer); //semCustomer--, == 0, 則阻塞Node* pDel = g_head;g_head = g_head->next;printf("-----funCustomer(消費者): %lu, %d\n", pthread_self(), pDel->data);delete pDel;sem_post(&semProducer); // semProducer++}return nullptr; }運行結果:
這個例子是在 uos20 上面運行的成功的;編譯的時候,記得加上參數(shù) -pthread 。
Mac 下對 sem_init()/sem_destory() 不支持:
注意:
MacOS 不支持 sem_init() 和 sem_destroy();這個例子若是想在 mac 下編譯通過,需要自行修改替換相關的函數(shù)。
- sem_init(&sem, 0, 1) 改成 sem_open("sem", O_CREAT|O_EXCL, S_IRWXU, 0)
- sem_destory(&sem) 改成 sem_unlink("sem");
- 且支持 pthread_mutex_init(&mutex, NULL) 卻不支持 pthread_mutex_destory(&mutex)
Mac 的該文件在 /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/semaphore.h 路徑,可以查看到該頭文件的源碼,附上詳細 mac 下該庫源碼:
#ifndef _SYS_SEMAPHORE_H_ #define _SYS_SEMAPHORE_H_typedef int sem_t;/* this should go in limits.h> */ #define SEM_VALUE_MAX 32767 #define SEM_FAILED ((sem_t *)-1)#include <sys/cdefs.h>__BEGIN_DECLS int sem_close(sem_t *); int sem_destroy(sem_t *) __deprecated; int sem_getvalue(sem_t * __restrict, int * __restrict) __deprecated; int sem_init(sem_t *, int, unsigned int) __deprecated; sem_t * sem_open(const char *, int, ...); int sem_post(sem_t *); int sem_trywait(sem_t *); int sem_unlink(const char *); int sem_wait(sem_t *) __DARWIN_ALIAS_C(sem_wait); __END_DECLS#endif /* _SYS_SEMAPHORE_H_ */下載地址:
21_semaphore
系列地址:
linuxExample 【21_semaphore】
歡迎 star 和 fork 這個系列的 Linux / Unix 學習,附學習由淺入深的目錄。
總結
以上是生活随笔為你收集整理的Linux中多线程使用信号量(信号灯),和sem_wait()函数使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 柳州细胞实验室局部建设规划
- 下一篇: linux 其他常用命令