深入淺出:信號燈與系統V信號燈的實現與應用

深入淺出:信號燈與系統V信號燈的實現與應用

信號燈(Semaphore)是一種同步機制,用于控制對共享資源的訪問。在多線程或多進程環境下,信號燈能夠幫助協調多個執行單元對共享資源的訪問,確保數據一致性與程序的正確執行。本文將從基本概念、常用API函數、以及有名和無名信號燈的差異講解信號燈的使用,適合新手理解并實踐。

1. 信號燈概述

信號燈是一種用來控制對共享資源的訪問的計數器,具有兩個主要操作:

  • P操作(sem_wait:請求資源,如果信號燈的值大于0,則成功獲取資源并將信號燈值減1。如果信號燈值為0,則會阻塞,直到信號燈的值大于0為止。
  • V操作(sem_post:釋放資源,將信號燈值加1。如果有其他進程或線程正在等待該信號燈,則喚醒其中一個。

這些操作通常用于解決臨界區問題,確保同一時刻只有一個線程或進程能夠訪問共享資源。

2. 有名與無名信號燈

2.1 有名信號燈

有名信號燈(Named Semaphore)是通過文件系統進行標識和訪問的信號燈。它通常用于進程間通信,因為不同進程可以通過訪問相同的文件路徑來使用這個信號燈。

2.1.1 關鍵API函數
  • sem_open:打開或創建有名信號燈。

    sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
    
    • name:信號燈的名稱(以 / 開頭)。
    • oflag:操作標志,如 O_CREAT 表示創建,O_EXCL 表示如果信號燈已存在則返回錯誤。
    • mode:權限模式(如 0666)。
    • value:信號燈的初始值。
  • sem_close:關閉信號燈。

    int sem_close(sem_t *sem);
    
  • sem_unlink:刪除有名信號燈。

    int sem_unlink(const char *name);
    
2.1.2 應用場景

有名信號燈適用于需要跨進程同步的場景。例如,多個進程需要訪問一個共享的硬件設備或共享的文件資源時,使用有名信號燈可以確保這些進程不會同時訪問,避免沖突。

2.2 無名信號燈

無名信號燈(Unnamed Semaphore)通常用于進程內或線程間同步,它們由進程中的內存地址來標識,且通常與進程或線程的生命周期綁定。

2.2.1 關鍵API函數
  • sem_init:初始化無名信號燈。

    int sem_init(sem_t *sem, int pshared, unsigned int value);
    
    • pshared:是否在進程間共享(0 表示線程間共享,非0表示進程間共享,通常用于多線程應用)。
    • value:信號燈的初始值。
  • sem_destroy:銷毀無名信號燈。

    int sem_destroy(sem_t *sem);
    
2.2.2 應用場景

無名信號燈通常用于多線程程序中,用于保護共享資源或者在多個線程間實現同步。由于無名信號燈的生命周期與進程或線程綁定,因此它們無法在進程之間共享。

3. 有名信號燈 vs 無名信號燈

特性有名信號燈無名信號燈
作用范圍進程間共享線程間共享,或進程間共享(需共享內存)
標識方式文件系統路徑名內存地址
創建方式sem_opensem_init
生命周期與文件系統綁定與進程或線程綁定
適用場景進程間同步線程間同步,或進程間同步(需共享內存)

4. 信號燈操作詳解

4.1 sem_wait(P 操作)

sem_wait 函數實現了信號燈的減操作(P 操作),它是阻塞的,直到信號燈的值大于0才會繼續執行。

int sem_wait(sem_t *sem);
  • 如果信號燈的值大于0,sem_wait 會將其減1,表示成功獲取資源。
  • 如果信號燈的值為0,當前進程或線程會阻塞,直到其他進程或線程釋放資源(通過 sem_post)。

4.2 sem_post(V 操作)

sem_post 函數實現了信號燈的加操作(V 操作),它用于釋放資源。

int sem_post(sem_t *sem);
  • 將信號燈的值加1,表示資源已經釋放。
  • 如果有其他進程或線程正在等待該信號燈,sem_post 會喚醒其中一個。

5. 生產者消費者模型示例

生產者消費者問題是一個經典的同步問題,生產者和消費者共享一個有限大小的緩沖區,生產者不斷生產數據并將其放入緩沖區,而消費者不斷消費數據并從緩沖區中取出數據。這個過程需要使用信號燈來協調生產者與消費者的行為,避免出現“緩沖區滿”或“緩沖區空”的情況。

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>#define BUFFER_SIZE 10int buffer[BUFFER_SIZE]; // 共享緩沖區
int count = 0; // 緩沖區中的數據數量sem_t empty; // 空閑緩沖區信號燈
sem_t full;  // 已占用緩沖區信號燈
sem_t mutex; // 互斥信號燈,保護共享資源void* producer(void* arg) {for (int i = 0; i < 20; i++) {sem_wait(&empty); // P操作,等待空閑緩沖區sem_wait(&mutex); // P操作,獲取鎖// 生產數據buffer[count] = i;count++;printf("Produced: %d\n", i);sem_post(&mutex); // V操作,釋放鎖sem_post(&full);  // V操作,增加已占用緩沖區}return NULL;
}void* consumer(void* arg) {for (int i = 0; i < 20; i++) {sem_wait(&full); // P操作,等待已占用緩沖區sem_wait(&mutex); // P操作,獲取鎖// 消費數據int item = buffer[count - 1];count--;printf("Consumed: %d\n", item);sem_post(&mutex); // V操作,釋放鎖sem_post(&empty); // V操作,增加空閑緩沖區}return NULL;
}int main() {pthread_t prod_tid, cons_tid;// 初始化信號燈sem_init(&empty, 0, BUFFER_SIZE); // 初始值為緩沖區大小sem_init(&full, 0, 0); // 初始值為 0sem_init(&mutex, 0, 1); // 初始值為 1(互斥信號燈)// 創建生產者和消費者線程pthread_create(&prod_tid, NULL, producer, NULL);pthread_create(&cons_tid, NULL, consumer, NULL);// 等待線程結束pthread_join(prod_tid, NULL);pthread_join(cons_tid, NULL);// 銷毀信號燈sem_destroy(&empty);sem_destroy(&full);sem_destroy(&mutex);return 0;
}

5.1 程序說明

  • empty 信號燈表示緩沖區中空閑的槽位,初始值為緩沖區大小。
  • full 信號燈表示緩沖區中已占用的槽位,初始值為0。
  • mutex 信號燈用于實現互斥鎖,保護共享資源(緩沖區)不被同時訪問。

生產者線程通過 sem_wait(&empty)sem_post(&full) 來協調緩沖區的生產過程,而消費者線程通過 sem_wait(&full)sem_post(&empty) 來協調消費過程。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901132.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901132.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901132.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

消防設施操作員崗位注意事項有哪些?

消防設施操作員主要負責消防設施的操作、維護和管理等工作&#xff0c;其崗位注意事項涉及操作規范、設備維護、應急處理等多個關鍵領域&#xff0c;以下是具體內容&#xff1a; 操作規范方面 熟悉設備原理&#xff1a;要全面了解各類消防設施的工作原理、性能參數和操作方法…

SQL:Relationship(關系)

目錄 &#x1f517; 什么是 Relationship&#xff1f; 三種基本關系類型&#xff08;基于實體間的關系&#xff09;&#xff1a; 1. 一對一&#xff08;One-to-One&#xff09; 2. 一對多&#xff08;One-to-Many&#xff09; 3. 多對多&#xff08;Many-to-Many&#xf…

php偽協議

PHP 偽協議&#xff08;PHP Stream Wrapper&#xff09; PHP 的偽協議&#xff08;Protocol Wrapper&#xff09;是一種機制&#xff0c;允許開發者通過統一的文件訪問函數&#xff08;如 file_get_contents、fopen、include 等&#xff09;訪問不同類型的數據源&#xff0c;包…

當DRAM邂逅SSD:新型“DRAM+”存儲技術來了!

在當今快速發展的科技領域&#xff0c;數據存儲的需求日益增長&#xff0c;對存儲設備的性能和可靠性提出了更高的要求。傳統DRAM以其高速度著稱&#xff0c;但其易失性限制了應用范圍&#xff1b;而固態硬盤SSD雖然提供非易失性存儲&#xff0c;但在速度上遠不及DRAM。 為了解…

org.apache.spark.SparkException: Kryo serialization failed: Buffer overflow...

Spark異常&#xff1a;Kryo serialization failed: Buffer overflow. 1、問題描述 SparkSQL任務報錯如下&#xff1a; org.apache.spark.SparkException: Kryo serialization failed: Buffer overflow. Available: 0, required: xxx. To avoid this, increase spark.kryoseri…

編譯原理 實驗二 詞法分析程序自動生成工具實驗

文章目錄 實驗環境的準備實驗實驗預備知識分析案例所要做的任務實戰 實驗環境的準備 安裝flex 安裝MinGW MinGW Installation Manager頁面 apply changes 下載比較耗時 只看到了一個文件&#xff0c;復制過去 配置環境變量 使用gcc -v檢驗是否安裝完成 實驗 實驗預備知識…

BERT - 直接調用transformers.BertModel, BertTokenizerAPI不進行任何微調

本節代碼將使用 transformers 庫加載預訓練的BERT模型和分詞器&#xff08;Tokenizer&#xff09;&#xff0c;并處理文本輸入。 1. 加載預訓練模型和分詞器 from transformers import BertTokenizer, BertModelmodel_path "/Users/azen/Desktop/llm/models/bert-base-…

Python 質數篩選:從入門到優化的 5 種方法

質數&#xff08;Prime Number&#xff09;是指只能被 1 和自身整除的自然數&#xff0c;如 2、3、5、7 等。在算法題、密碼學或數學計算中&#xff0c;高效生成質數至關重要。 Python 提供了多種方法來實現質數篩選&#xff0c;但不同方法的效率差異巨大。本文從 最基礎的方法…

C#MQTT協議服務器與客戶端通訊實現(客戶端包含斷開重連模塊)

C#MQTT協議服務器與客戶端通訊實現 1 DLL版本2 服務器3 客戶端 1 DLL版本 MQTTnet.DLL版本-2.7.5.0 基于比較老的項目中應用的DLL&#xff0c;其他更高版本變化可能較大&#xff0c;謹慎參考。 2 服務器 開啟服務器 關閉服務器 綁定事件【客戶端連接服務器事件】 綁定事件【客戶…

【連載3】基礎智能體的進展與挑戰綜述

基礎智能體的進展與挑戰綜述 從類腦智能到具備可進化性、協作性和安全性的系統 【翻譯團隊】劉軍(liujunbupt.edu.cn) 錢雨欣玥 馮梓哲 李正博 李冠諭 朱宇晗 張霄天 孫大壯 黃若溪 2. 認知 人類認知是一種復雜的信息處理系統&#xff0c;它通過多個專門的神經回路協調運行…

Python語言介紹

Python 是一種高級、通用、解釋型的編程語言&#xff0c;由 Guido van Rossum 于 1991 年首次發布。其設計哲學強調代碼的可讀性和簡潔性。 Python通過簡潔的語法和強大的生態系統&#xff0c;成為當今最受歡迎的編程語言之一。 一、核心特點 Python 是一種解釋型、面向對象、…

什么是回表?哪些數據庫存在回表?

目錄 一、什么是回表1. 回表的核心流程2. 示例說明3. 回表的性能問題4. 總結 二、哪些數據庫會有回表1. MySQL&#xff08;InnoDB&#xff09;2. Oracle3. 其他數據庫&#xff08;如 SQL Server、PostgreSQL&#xff09;4. 總結 三、非聚集索引與聚集索引的區別及產生原因1. 聚…

ssh 免密登錄服務器(vscode +ssh 免密登錄)

每次打開vscode連接服務器都需要輸入密碼&#xff0c;特別繁瑣。 然后自己在網上翻閱了一下教程&#xff0c;發現說的內容比較啰嗦&#xff0c;而且個人感覺非常有誤導性傾向。 因此自己直接干脆寫一個簡便易懂的教程算了。 &#xff08;以經過本人親測&#xff0c;真實可靠&am…

基于低空經濟的無人機操控與維護實訓室解決方案

一、低空經濟時代下的無人機人才需求 1.1 低空經濟發展趨勢與政策機遇 在當前經濟與科技飛速發展的大背景下&#xff0c;低空經濟作為國家戰略性新興產業&#xff0c;正以迅猛之勢崛起&#xff0c;展現出無限的潛力與活力。其應用場景極為廣泛&#xff0c;涵蓋了物流、安防、…

PyTorch實現二維卷積與邊緣檢測:從原理到實戰

本文通過PyTorch實現二維互相關運算、自定義卷積層&#xff0c;并演示如何通過卷積核檢測圖像邊緣。同時&#xff0c;我們將訓練一個卷積核參數&#xff0c;使其能夠從數據中學習邊緣特征。 1. 二維互相關運算的實現 互相關運算&#xff08;Cross-Correlation&#xff09;是卷…

數字政府網絡架構建設方案

數字政府網絡架構建設方案 一、引言 隨著信息技術的快速發展&#xff0c;數字政府建設已成為提升政府治理能力和服務水平的關鍵。網絡架構作為數字政府的核心基礎設施&#xff0c;對于保障數據安全、提高服務效率、促進信息共享具有重要意義。本方案旨在為數字政府網絡架構建…

Python map函數介紹

在 Python 里&#xff0c;map() 是一個內置函數&#xff0c;其用途是將指定的函數應用于可迭代對象&#xff08;像列表、元組等&#xff09;的每個元素&#xff0c;最終返回一個新的迭代器。此迭代器所包含的元素是原可迭代對象中每個元素經過指定函數處理后的結果。map() 函數…

【服務器端表單字符驗證】

文章目錄 一、實驗目的二、核心代碼實現三、調試關鍵問題四、總結 一、實驗目的 掌握JSP表單驗證在服務器端的實現技術&#xff0c;實現對用戶輸入字符的非空及長度為5的驗證&#xff0c;返回對應提示信息并優化用戶交互。 二、核心代碼實現 前端表單 <form action"…

dify windos,linux下載安裝部署,提供百度云盤地址

dify下載安裝 dify1.0.1 windos安裝包百度云盤地址 通過網盤分享的文件&#xff1a;dify-1.0.1.zip 鏈接: 百度網盤 請輸入提取碼 提取碼: 1234 dify安裝包 linux安裝包百度云盤地址 通過網盤分享的文件&#xff1a;dify-1.0.1.tar.gz 鏈接: 百度網盤 請輸入提取碼 提取碼…

C++ Primer 5e 習題2.5: 指出如下字面量常量的類型

Exercise 2.5: Determine the type of each of the following literals. Explain the differences among the literals in each of the four examples: (a) ‘a’, L’a’, “a”, L"a" (b) 10, 10u, 10L, 10uL, 012, 0xC © 3.14, 3.14f, 3.14L (d) 10, 10u, 10…