日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux中多线程使用信号量(信号灯),和sem_wait()函数使用

發(fā)布時間:2024/3/24 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux中多线程使用信号量(信号灯),和sem_wait()函数使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

      • 編程環(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ù)

  • 加鎖:

    //調(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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。