兩個程序配合實現了基于共享內存和信號量的進程間通信,具體說明如下:

第一個程序:共享內存讀取程序(消費者)

該程序作為消費者,從共享內存中讀取數據,通過信號量保證只有當生產者寫入數據后才能讀取。

/*4 - 讀共享內存*/
#include<stdio.h>                  // 標準輸入輸出庫
#include<stdlib.h>                 // 標準庫,包含exit等函數
#include<unistd.h>                 // 包含UNIX系統調用,如sleep
#include <sys/types.h>             // 定義系統數據類型
#include <sys/ipc.h>               // 包含IPC(進程間通信)相關函數定義
#include <sys/shm.h>               // 共享內存相關函數定義
#include <sys/sem.h>               // 信號量相關函數定義
#include <string.h>                // 字符串處理函數庫int main()
{//1、確定 文件路徑名 ---獲取消息隊列的key值key_t key = ftok(".", 'a');    // 用當前目錄和字符'a'生成唯一key值,用于標識共享內存和信號量if(key == -1){                 // 檢查ftok函數調用是否失敗perror("ftok error");      // 輸出錯誤信息return -1;                 // 程序異常退出}//2、根據key值 獲取共享內存的ID,如果共享內存不存在則創建// IPC_CREAT表示不存在則創建,0666表示權限(所有者、組、其他用戶都可讀寫)int shmid = shmget(key,100,IPC_CREAT|0666);  if(shmid==-1){                 // 檢查shmget函數調用是否失敗perror("shmget");          // 輸出錯誤信息exit(-1);                  // 程序異常退出}//根據key創建/獲取信號量集,創建1個信號量int semid = semget(key,1,IPC_CREAT|0666);  if(semid==-1){                 // 檢查semget函數調用是否失敗perror("semget");          // 輸出錯誤信息exit(-1);                  // 程序異常退出}//3.映射共享內存到當前進程的地址空間,第二個參數0表示由系統自動分配地址void *p = shmat(shmid,0,0);    if(p==(void *)-1){             // 檢查shmat函數調用是否失敗perror("shmat");           // 輸出錯誤信息exit(-1);                  // 程序異常退出}//4.使用共享內存(消費者邏輯)struct sembuf buf;             // 定義信號量操作結構體while(1){                      // 無限循環,持續讀取數據buf.sem_num = 0;           // 操作第0個信號量(信號量集索引)buf.sem_op = -1;           // 執行P操作(申請資源,信號量值減1)buf.sem_flg = 0;           // 0表示阻塞模式,若資源不可用則等待semop(semid,&buf,1);       // 執行信號量操作printf("data = %d\n",*(int *)p);  // 從共享內存讀取整數并打印}//5.不再使用可以解除映射(實際不會執行,因為上面是無限循環)shmdt(p);//6.不再需要可以刪除共享內存(注釋掉表示不自動刪除)//shmctl(shmid,IPC_RMID,0);return 0;
}

第二個程序:共享內存寫入程序(生產者)

該程序作為生產者,向共享內存中寫入數據,通過信號量通知消費者可以讀取數據。

/*5 - 信號量集保護共享內存*/
#include<stdio.h>                  // 標準輸入輸出庫
#include<stdlib.h>                 // 標準庫,包含exit等函數
#include<unistd.h>                 // 包含UNIX系統調用,如sleep
#include <sys/types.h>             // 定義系統數據類型
#include <sys/ipc.h>               // 包含IPC(進程間通信)相關函數定義
#include <sys/shm.h>               // 共享內存相關函數定義
#include <string.h>                // 字符串處理函數庫
#include <sys/sem.h>               // 信號量相關函數定義int main()
{//1、確定 文件路徑名 ---獲取消息隊列的key值key_t key = ftok(".", 'a');    // 用當前目錄和字符'a'生成唯一key值,與消費者保持一致if(key == -1){                 // 檢查ftok函數調用是否失敗perror("ftok error");      // 輸出錯誤信息return -1;                 // 程序異常退出}//2、根據key值 獲取共享內存的ID,如果共享內存不存在則創建// IPC_CREAT表示不存在則創建,0666表示權限(所有者、組、其他用戶都可讀寫)int shmid = shmget(key,100,IPC_CREAT|0666);  if(shmid==-1){                 // 檢查shmget函數調用是否失敗perror("shmget");          // 輸出錯誤信息exit(-1);                  // 程序異常退出}//根據key創建/獲取信號量集,創建1個信號量int semid = semget(key,1,IPC_CREAT|0666);  if(semid==-1){                 // 檢查semget函數調用是否失敗perror("semget");          // 輸出錯誤信息exit(-1);                  // 程序異常退出}//設置信號量的初始值為0(用于同步,初始狀態下沒有數據可讀)semctl(semid,0,SETVAL,0);//3.映射共享內存到當前進程的地址空間,第二個參數0表示由系統自動分配地址void *p = shmat(shmid,0,0);    if(p==(void *)-1){             // 檢查shmat函數調用是否失敗perror("shmat");           // 輸出錯誤信息exit(-1);                  // 程序異常退出}struct sembuf buf;             // 定義信號量操作結構體//生產者邏輯while(1){                      // 無限循環,持續寫入數據printf("請輸入一個整數:");  // 提示用戶輸入scanf("%d",(int *)p);      // 將用戶輸入的整數寫入共享內存buf.sem_num = 0;           // 操作第0個信號量(信號量集索引)buf.sem_op = 1;            // 執行V操作(釋放資源,信號量值加1)buf.sem_flg = 0;           // 0表示阻塞模式semop(semid,&buf,1);       // 執行信號量操作,通知消費者有新數據}//5.不再使用可以解除映射(實際不會執行,因為上面是無限循環)shmdt(p);//6.不再需要可以刪除共享內存(注釋掉表示不自動刪除)//shmctl(shmid,IPC_RMID,0);return 0;
}

兩個程序的整體作用

這兩個程序配合實現了基于共享內存和信號量的進程間通信,具體說明如下:

  1. 核心功能

    • 生產者程序(第二個)從用戶輸入獲取整數,寫入共享內存,并通過信號量通知消費者。
    • 消費者程序(第一個)通過信號量等待,當檢測到生產者寫入數據后,從共享內存讀取并打印該整數。
  2. 信號量的作用

    • 實現了生產者和消費者的同步:消費者必須等待生產者寫入數據后才能讀取,避免讀取到空數據或舊數據。
    • 信號量初始值為 0,生產者寫入數據后執行 V 操作(值 + 1),消費者讀取前執行 P 操作(值 - 1),確保數據讀寫順序正確。
  3. 共享內存的作用
    提供了一個兩個進程都能訪問的內存區域,實現高效的數據傳遞(相比管道等方式,共享內存無需數據拷貝,速度更快)。

通過這種機制,兩個獨立進程可以安全、有序地進行數據交換。


如果沒有 PV 操作(或類似的同步互斥機制),在多任務 / 多進程環境中會出現一系列嚴重問題,核心是共享資源訪問沖突任務執行順序混亂,具體表現如下:

1. 共享資源 “爭搶” 導致數據混亂(互斥問題)

假設有兩個任務同時操作一個共享變量(比如銀行賬戶余額):

  • 任務 A 要給賬戶加 100 元,讀取當前余額為 500 元,準備計算成 600 元;
  • 此時任務 B 突然介入,讀取余額還是 500 元,減去 50 元(計算成 450 元)并寫入;
  • 任務 A 接著執行,把自己計算的 600 元寫入。

最終余額變成 600 元(正確結果應為 500+100-50=550 元),數據被破壞。

沒有 PV 操作時,多個任務會 “同時” 搶占共享資源,導致操作交叉覆蓋,結果錯誤。

2. 任務執行順序失控(同步問題)

比如任務 A 負責采集傳感器數據,任務 B 負責處理數據:

  • 任務 B 可能在任務 A 還沒采集到數據時就開始處理,導致處理 “空數據”;
  • 任務 A 可能連續采集了多組數據,但任務 B 只處理了其中一部分,導致數據積壓或丟失。

沒有 PV 操作時,任務間缺乏 “等待 - 通知” 機制,無法按邏輯順序執行,系統功能紊亂。

3. 系統陷入 “死鎖” 或 “饑餓”

  • 死鎖:兩個任務分別占用對方需要的資源,且都不釋放,互相等待對方放手,導致系統卡死。例如:任務 A 占用打印機,等待掃描儀;任務 B 占用掃描儀,等待打印機,兩者永遠僵持。
  • 饑餓:高優先級任務持續搶占資源,低優先級任務永遠得不到執行機會(比如一個后臺統計任務始終無法運行)。

沒有 PV 操作時,無法合理分配資源使用權,容易出現這類極端問題。

4. 實時系統失去 “實時性”

在實時系統(如工業控制、自動駕駛)中,任務必須在嚴格時間內響應。

  • 若多個任務無序爭搶 CPU 或外設,關鍵任務(如緊急剎車控制)可能被低優先級任務打斷,導致響應超時,引發安全事故。

沒有 PV 操作時,無法保證高優先級任務的優先執行權,實時性無從談起。

總結

PV 操作(及信號量機制)是多任務系統的 “交通規則”:

  • 沒有規則,車輛(任務)會亂搶車道(資源),導致撞車(數據錯誤)、堵車(死鎖)、緊急車輛被堵(實時性失效)。
  • 因此,任何支持多任務的系統(如 μC/OS、Linux 內核)都必須有類似 PV 操作的同步互斥機制,否則根本無法穩定運行。


P 和 V 是荷蘭語 “Proberen” 和 “Verhogen” 的縮寫)。在操作系統和多任務編程中,PV 操作是配合信號量使用的一組原子操作,主要作用是實現任務間的同步與互斥,確保共享資源的安全訪問。

具體作用可以用兩個生活場景理解:

1. 實現 “互斥”:防止多個任務同時操作共享資源

比如多個任務需要使用同一個打印機(共享資源):

  • P 操作:相當于 “申請使用打印機”。如果打印機空閑(信號量 > 0),任務占用它;如果被占用(信號量 = 0),任務就排隊等待,不能強行使用。
  • V 操作:相當于 “用完打印機歸還”。釋放打印機后,通知排隊的任務 “現在可以使用了”。

通過 PV 操作,能保證同一時間只有一個任務使用打印機,避免打印內容混亂。

2. 實現 “同步”:控制任務的執行順序

比如任務 A 需要先生產數據,任務 B 才能處理數據:

  • 任務 A 生產完數據后,執行V 操作(相當于 “通知 B 可以處理了”)。
  • 任務 B 開始前執行P 操作(相當于 “等待 A 的通知”),如果沒收到通知(信號量 = 0),就暫停等待,直到 A 通知后再執行。

通過 PV 操作,能確保 B 在 A 完成后才執行,避免 B 因沒數據而 “做無用功”。

總結

PV 操作的核心作用是通過信號量的 “申請 - 釋放” 機制,協調多個任務的執行節奏

  • 防止多個任務同時操作共享資源(互斥);
  • 保證任務按預期順序執行(同步);
  • 避免數據混亂、資源沖突等問題,讓多任務系統穩定運行。

這在嵌入式系統(如 μC/OS)、操作系統內核等場景中非常重要。

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

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

相關文章

JeecgBoot(1):前后臺環境搭建

1 項目介紹 JeecgBoot 是一款基于 Java 的 AI 低代碼平臺&#xff0c;它采用了 SpringBoot、SpringCloud、Ant Design Vue3、Mybatis 等技術棧&#xff0c;并集成了代碼生成器、AI 對話助手、AI 建表、AI 寫文章等功能。JeecgBoot 的設計宗旨是實現簡單功能零代碼開發&#xf…

Nestjs框架: 關于 OOP / FP / FRP 編程

概述 在軟件開發過程中&#xff0c;不同的編程范式為我們提供了多樣化的思維方式與實現路徑它們不僅影響著代碼的結構和邏輯組織方式&#xff0c;也深刻影響著項目的可維護性、可擴展性以及團隊協作效率 什么是 OOP、FP 和 FRP&#xff1f;首先從三個術語的含義入手 1 &#xf…

elememtor 添加分頁功能

各位看官好&#xff0c;最近在忙著使用elementor搭建自己的網站&#xff0c;由于我不是專業的程序員和前端&#xff0c;又沒有很多錢去找外包公司實現自己的設計&#xff0c;所以選擇了elementor. 總的來說這是一個不錯的wordpress 插件&#xff0c;也讓我們這種非專業的網站設…

關于“PromptPilot” 之2 -目標系統:Prompt構造器

目標系統&#xff1a;Prompt構造器想法首先&#xff0c;在抽象層對PromptPilot進行封裝給出提示詞形成過程的全部環節。然后&#xff0c;在 形成一套確定的提示詞后再為 小規模試點方案生成一整套開發工具并配套集成開發環境和指南。最后&#xff0c;在小規模試點成功后進行拓展…

短劇小程序系統開發:重塑影視內容消費格局

在數字化浪潮的推動下&#xff0c;影視內容消費正經歷著深刻的變革。短劇小程序系統開發作為這一變革的重要力量&#xff0c;正在重塑影視內容消費的格局&#xff0c;為用戶帶來更加個性化、便捷化的觀影體驗。傳統影視內容消費往往受到時間和空間的限制&#xff0c;用戶需要前…

一文掌握最新版本Monocle3單細胞軌跡(擬時序)分析

許多大佬的軟件想要構建一個大而美的生態&#xff0c;從 monocle2 開始就能做單細胞的質控、降維、分群、注釋這一系列的分析&#xff0c;但不幸的是我們只知道 monocle 系列還是主要做擬時序分析&#xff0c;一方面是因為 Seurat 有先發優勢&#xff0c;出名要趁早&#xff0c…

spark入門-helloword

我們學習編程語言的時候&#xff0c;第一個程序就是打印一下 “hello world” &#xff0c;對于大數據領域的第一個任務則是wordcount。那我們就開始我們的第一個spark任務吧&#xff01; 下載spark 官方下載地址&#xff1a;Apache Download Mirrors 下載完畢以后&#xff0c…

雷達系統設計學習:自制6GHz FMCW Radar

國外大神自制6GHZ FMCW Radar開源項目: https://github.com/Ttl/fmcw3 引言 之前我做過一個簡單的調頻連續波&#xff08;FMCW&#xff09;雷達&#xff0c;能夠探測到100米范圍內人體大小的物體。雖然它確實能用&#xff0c;但由于預算有限&#xff0c;還有很大的改進空間。 …

系統選擇菜單(ubuntu grub)介紹

好的&#xff0c;我們來詳細解釋一下什么是Ubuntu的GRUB菜單。 簡單來說&#xff0c;GRUB菜單是您電腦啟動時看到的第一個交互界面&#xff0c;它就像一個“系統選擇”菜單&#xff0c;讓您決定接下來要啟動哪個操作系統或進入哪種模式。詳細解釋 1. GRUB是什么&#xff1f; GR…

方案C,version2

實現一個簡單的Helloworld網頁,并通過GitHub Actions自動構建并推送到公開倉庫的gh-pages分支。同時,使用PAT進行認證,確保源碼在私有倉庫中,構建后的靜態文件在公開倉庫中。 重新設計deploy.yml內容如下(針對純靜態文件,無需構建過程): 步驟: 檢出私有倉庫源碼。 由于…

R 語言科研繪圖 --- 其他繪圖-匯總1

在發表科研論文的過程中&#xff0c;科研繪圖是必不可少的&#xff0c;一張好看的圖形會是文章很大的加分項。 為了便于使用&#xff0c;本系列文章介紹的所有繪圖都已收錄到了 sciRplot 項目中&#xff0c;獲取方式&#xff1a; R 語言科研繪圖模板 --- sciRplothttps://mp.…

webpack 原理及使用

【點贊收藏加關注,前端技術不迷路~】 一、webpack基礎 1.核心概念 1)entry:定義入口,webpack構建的第一步 module.exports ={entry:./src/xxx.js } 2)output:出口(輸出) 3)loader:模塊加載器,用戶將模塊的原內容按照需求加載成新內容 比如文本加載器raw-loade…

「日拱一碼」039 機器學習-訓練時間VS精確度

目錄 時間-精度權衡曲線&#xff08;不同模型復雜度&#xff09; 訓練與驗證損失對比 帕累托前沿分析&#xff08;3D&#xff09; 在機器學習實踐中&#xff0c;理解模型收斂所需時間及其與精度的關系至關重要。下面介紹如何分析模型收斂時間與精度之間的權衡&#xff0c;并…

面試刷題平臺項目總結

項目簡介&#xff1a; 面試刷題平臺是一款基于 Spring Boot Redis MySQL Elasticsearch 的 面試刷題平臺&#xff0c;運用 Druid HotKey Sa-Token Sentinel 提高了系統的性能和安全性。 第一階段&#xff0c;開發基礎的刷題平臺&#xff0c;帶大家熟悉項目開發流程&#xff…

負載均衡、算法/策略

負載均衡一、負載均衡層級對比特性四層負載均衡 (L4)七層負載均衡 (L7)工作層級傳輸層 (TCP/UDP)應用層 (HTTP/HTTPS等)決策依據源/目標IP端口URL路徑、Header、Cookie、內容等轉發方式IP地址/端口替換重建連接并深度解析報文性能更高吞吐量&#xff0c;更低延遲需內容解析&…

StackingClassifier參數詳解與示例

StackingClassifier參數詳解與示例 StackingClassifier是一種集成學習方法&#xff0c;通過組合多個基分類器的預測結果作為元分類器的輸入特征&#xff0c;從而提高整體模型性能。以下是關鍵參數的詳細說明和示例&#xff1a; 1. classifiers&#xff08;基分類器&#xff09;…

嵌入式中間件-uorb解析

uORB系統詳細解析 1. 系統概述 1.1 設計理念 uORB&#xff08;Micro Object Request Broker&#xff09;是一個專為嵌入式實時系統設計的發布-訂閱式進程間通信框架。該系統借鑒了ROS中topic的概念&#xff0c;為無人機飛控系統提供了高效、可靠的數據傳輸機制。 1.2 核心特征 …

HTTP.Client 庫對比與選擇

HTTP.Client 庫對比與選擇在 Python 中&#xff0c;除了標準庫 http.client&#xff0c;還有許多功能更強大、使用更便捷的 HTTP 庫。以下是一些常用的庫及其特點&#xff1a;1. Requests&#xff08;最流行&#xff09;特點&#xff1a;高層 API&#xff0c;簡單易用&#xff…

RabbitMQ面試精講 Day 5:Virtual Host與權限控制

【RabbitMQ面試精講 Day 5】Virtual Host與權限控制 開篇 歡迎來到"RabbitMQ面試精講"系列的第5天&#xff01;今天我們將深入探討RabbitMQ中Virtual Host與權限控制的核心機制&#xff0c;這是構建安全、隔離的消息系統必須掌握的重要知識。在面試中&#xff0c;面…

【前端實戰】純HTML+CSS+JS實現蠟筆小新無盡冒險:從零打造網頁版超級瑪麗

摘要&#xff1a;本文將詳細介紹一款完全由HTMLCSSJS實現的網頁版橫版闖關游戲——"蠟筆小新無盡冒險"。游戲采用純前端技術實現&#xff0c;無需任何外部依賴&#xff0c;完美復刻了經典超級瑪麗的核心玩法&#xff0c;并創新性地融入了蠟筆小新角色元素。通過本文&…