IO進程線程(九)線程的同步 進程間通信

文章目錄

  • 一、 線程的同步
    • (一)無名信號量sem
      • 1. 定義和初始化
      • 2.獲取信號量
      • 3.釋放信號量
      • 4. 銷毀
      • 5. 使用示例
    • (二)條件變量
      • 1. 定義和初始化
      • 2. 獲取條件變量
      • 3. 釋放條件變量
      • 4. 銷毀條件變量
  • 二、進程間通信
    • (一)無名管道
      • 1.概念
      • 2. 定義
      • 3. 特點
    • (二)有名管道
      • 1. 原理
      • 2. 定義
      • 3. 特點
    • (三)信號通信
      • 1. 概念
      • 2. 定義

一、 線程的同步

線程同步:提前已經知道了線程應該有的執行的順序,控制線程按指定的順序執行

互斥鎖無法保證線程執行的順序,一個線程解鎖后無法保證是另一個線程上鎖,有可能仍是原來剛解鎖的線程又再次上鎖

無名信號量是荷蘭計算器科學家發明的,PV操作的PV來自荷蘭語。

(一)無名信號量sem

1. 定義和初始化

#include <semaphore.h>定義無名信號量sem_t  sem;
初始化無名信號量int sem_init(sem_t *sem, int pshared, unsigned int value);功能:初始化無名信號量參數:sem:無名信號量指針pshared:0:兩個線程間同步非0:兩個進程間同步value:信號量的初始值如果是1表示可以獲取信號量如果是0表示不可以獲取信號量返回值:成功 0失敗 -1 重置錯誤碼 

2.獲取信號量

獲取信號量(P操作)int sem_wait(sem_t *sem);功能:獲取信號量 (將信號量的值-1)如果信號量的值已經是0了,則sem_wait會阻塞,等到能執行減1操作為止參數:sem:無名信號量指針返回值:成功 0失敗 不會改變信號量的值 返回 -1 重置錯誤碼 

3.釋放信號量

釋放信號量(V操作)int sem_post(sem_t *sem);功能:釋放信號量(將信號量的值+1)參數:sem:無名信號量指針返回值:成功 0失敗 不會改變信號量的值 返回 -1 重置錯誤碼 

4. 銷毀

銷毀無名信號量int sem_destroy(sem_t *sem);功能:銷毀無名信號量參數:sem:無名信號量指針返回值:成功 0
  • 注:
  • 無名信號量不允許減到小于1,當等于0時,sem_wait會阻塞等待;
  • 但是無名信號量允許加到大于1

5. 使用示例

現有三個線程,其功能分別為打印A、打印B、打印C,使用無名信號量使其按照ABC的順序打印。

#include <my_head.h>sem_t sem1;
sem_t sem2;
sem_t sem3;//A線程
void *task_func_1(void *arg){while(1){sem_wait(&sem1);sleep(1);printf("A ");fflush(stdout);sem_post(&sem2);}
}//B線程
void *task_func_2(void *arg){while(1){sem_wait(&sem2);sleep(1);printf("B ");fflush(stdout);sem_post(&sem3);}
}
//C線程
void *task_func_3(void *arg){while(1){sem_wait(&sem3);sleep(1);printf("C ");fflush(stdout);sem_post(&sem1);}
}int main(int argc, const char *argv[])
{//初始化無名信號量sem_init(&sem1, 0, 1);sem_init(&sem2, 0, 0);sem_init(&sem3, 0, 0);pthread_t tid1 = 0, tid2 = 0, tid3=0;int ret = 0;if(0 != (ret = pthread_create(&tid1, NULL, task_func_1, NULL))){printf("pthread_create error : %s\n", strerror(ret));exit(-1);}if(0 != (ret = pthread_create(&tid2, NULL, task_func_2, NULL))){printf("pthread_create error : %s\n", strerror(ret));exit(-1);}if(0 != (ret = pthread_create(&tid3, NULL, task_func_3, NULL))){printf("pthread_create error : %s\n", strerror(ret));exit(-1);}pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);//銷毀無名信號量sem_destroy(&sem1);sem_destroy(&sem2);sem_destroy(&sem3);return 0;
}

(二)條件變量

無名信號量適合線程數比較少的線程中實現微觀的同步過程,
條件變量更適用于大量線程實現同步

1. 定義和初始化

#include <pthread.h>pthread_cond_t cond;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//靜態初始化
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
功能:動態初始化條件變量
參數:cond:條件變量指針cond_attr:條件變量的屬性 NULL 表示使用默認屬性
返回值:成功 0  失敗 錯誤碼

2. 獲取條件變量

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
功能:獲取條件變量
參數:cond:條件變量指針mutex:互斥鎖指針
返回值:成功 0  失敗 錯誤碼
使用流程:1.先獲取到互斥鎖(可以先完成一些任務初始化的工作)2.調用pthread_cond_wait2.1 將當前線程添加到隊列中2.2 解鎖2.3 在隊列中休眠2.4 重新獲取鎖這時,如果等待的條件沒有發生,會繼續解鎖、休眠如果等待的條件發生了,會將線程在隊列中移除3.執行后續的任務4.解鎖

3. 釋放條件變量

int pthread_cond_signal(pthread_cond_t *cond);
功能:釋放一個條件變量,喚醒一個等待條件的線程
參數:cond:條件變量指針
返回值:成功 0  失敗 錯誤碼int pthread_cond_broadcast(pthread_cond_t *cond);
功能:釋放所有的資源,喚醒所有等待條件的線程
參數:cond:條件變量指針
返回值:成功 0  失敗 錯誤碼

4. 銷毀條件變量

int pthread_cond_destroy(pthread_cond_t *cond);
功能:銷毀條件變量
參數:cond:條件變量指針
返回值:成功 0  失敗 錯誤碼

二、進程間通信

進程間通信方式
1.傳統進程間通信
無名管道
有名管道
信號通信
2.system V 版本引入了IPC進程間通信
消息隊列
共享內存
信號燈集
socket套接字通信

(一)無名管道

1.概念

在使用fork函數創建子進程前打開的文件描述符,在fork之后,子進程會繼承父進程打開的文件描述符。
在這里插入圖片描述

無名管道是內核空間實現的機制,只能用于親緣進程間通信,無名管道的大小是64K。

2. 定義

#include <unistd.h>
int pipe(int pipefd[2]);
功能:創建一個管道 一個單向的數據通道 可用于進程間通信數組 pipefd 中會返回兩個文件描述符,pipefd[0] 管道的讀端  pipefd[1] 管道的寫端寫入管道的數據會被內核緩沖 直到被讀走
參數:pipefd:保存管道的兩個端點的文件描述符的數據
返回值:成功  0失敗 -1 重置錯誤碼

3. 特點

1.只能用于親緣間進程的通信
2.無名管道數據半雙工的通信的方式
單工 : A -------------->B
半雙工 : 同一時刻 A----->B B------>A
全雙工 : 同一時刻 A<---->B
3.無名管道的大小是64K
4.無名管道不能夠使用lseek函數(調用會出錯 返回 -1)
5.讀寫的特點
如果讀端存在 寫管道:有多少寫多少,直到寫滿為止(64k)寫阻塞,
直到管道中騰出新的4K空間,寫操作解除阻塞
如果讀端不存在 寫管道,管道破裂(SIGPIPE)
如果寫端存在 讀管道:有多少讀多少,沒有數據的時候阻塞等待
如果寫端不存在 讀管道:有多少讀多少,沒有數據的時候立即返回(非阻塞)

(二)有名管道

1. 原理

有名管道會在文件系統中創建一個管道文件,只需要打開這個文件,進行讀寫操作即可。
有名管道是在文件系統中映射出一個管道文件名,管道文件本質是在內存上的,在硬盤上的只是一個標識。
在這里插入圖片描述

2. 定義

mkfifo命令也可以創建管道文件
管道文件不能重名
在管道文件中寫入內容,文件大小并不會增加,因為寫入管道文件的內容保存在內存中,并非硬盤中

//也可以在終端上使用 mkfifo 命令創建管道文件
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:
參數:pathname:管道文件的路徑和名字mode:權限   & ~umask  --》 最終權限
返回值:成功  0失敗  -1 重置錯誤碼

3. 特點

  1. 可以用于任意進程間的通信,不僅限親緣進程
  2. 有名管道數據是半雙工的通信方式
  3. 有名管道的大小是64K
  4. 有名管道不能夠使用lseek函數(調用會失敗 返回 -1)
  5. 讀寫的特點
    如果讀端存在寫管道:有多少寫多少,直到寫滿為止(64k)寫阻塞
    如果讀端不存在寫管道
    1.讀端沒有打開,寫端在open的位置阻塞
    2.讀端打開后關閉,管道破裂(SIGPIPE)
    如果寫端存在讀管道:有多少讀多少,沒有數據的時候阻塞等待
    如果寫端不存在讀管道
    1.寫端沒有打開,讀端在open的位置阻塞
    2.寫端打開后關閉,有多少讀多少,沒有數據的時候立即返回

(三)信號通信

1. 概念

信號是中斷的一種軟件模擬,中斷是基于硬件的概念,信號是基于linux內核實現的。
用戶可以給進程發信號,進程可以給進程發信號,linux內核也可以給進程發信號。
信號的處理方式有三種:默認DEF、忽略IGN、捕捉 caught
man 7 signal

信號查看:kill -l
在這里插入圖片描述

2. 定義

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:注冊信號和信號處理方式的關系
參數:signum:信號的編號handler:處理方式SIG_IGN  忽略SIG_DFL  默認也可以傳一個函數  捕捉void sig_func(int signum){//自定義的邏輯}
返回值:成功  返回handler失敗  SIG_ERR  重置錯誤碼

signal函數只是注冊了信號和處理方式的關系,并不會阻塞等待信號產生

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

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

相關文章

web-上傳項目文件夾到Git遠程倉庫

Git初識 概念&#xff1a;一個免費開源&#xff0c;分布式的代碼版本控制系統&#xff0c;幫助開發團隊維護代碼 作用&#xff1a;記錄代碼內容&#xff0c;切換代碼版本&#xff0c;多人開發時高效合并代碼內容 檢驗成功 打開bash終端&#xff08;git專用&#xff09;命令…

12. MySQL 日志

文章目錄 【 1. 日志的基本原理 】【 2. 錯誤日志 Error Log 】2.1 啟動和設置錯誤日志2.2 查看錯誤日志2.3 刪除錯誤日志 【 3. 二進制日志 Binary Log 】3.1 啟動和設置二進制日志3.2 查看二進制日志3.3 刪除二進制文件刪除所有二進制日志刪除小于指定編號的二進制日志刪除創…

【vue3+pinia+uniapp項目問題:使用pinia狀態管理時store的數據更新,模板渲染視圖不能實時更新】

在這里選擇不同的學校后&#xff0c;發現store里面的數據打印出來能更新&#xff0c;但是使用store的數據打印出來并未實時更新且渲染在模板上&#xff0c;必須手動刷新視圖才能更新。 原因是因為使用了解構賦值傳入參數 解決方法 1.使用computed 現在視圖能進行實時更新…

分享一個 .Net core Console 項目使用 SqlSugar 的詳細例子

前言 SqlSugar 是一款老牌的 .NET 開源 ORM 框架&#xff0c;性能高&#xff0c;功能全面&#xff0c;使用簡單&#xff0c;支持 .NET FrameWork、.NET Core3.1、.NET5、.NET6、.NET7、.NET8、.NET9 等版本&#xff0c;線上論壇非常活躍&#xff0c;今天給大伙分享一個 .Net c…

查看遠程桌面端口,查看服務器的遠程桌面端口的方法

如果你正在尋找一種方法來檢查服務器的遠程桌面端口&#xff0c;那么請務必按照以下步驟操作&#xff0c;以確保準確且安全地獲取所需信息。這不僅是一個技術問題&#xff0c;更是一個關于效率和安全性的重要議題。 首先&#xff0c;你需要明確&#xff0c;遠程桌面端口通常是…

回溯算法之遞增子數列

題目&#xff1a; 給你一個整數數組 nums &#xff0c;找出并返回所有該數組中不同的遞增子序列&#xff0c;遞增子序列中 至少有兩個元素 。你可以按 任意順序 返回答案。 數組中可能含有重復元素&#xff0c;如出現兩個整數相等&#xff0c;也可以視作遞增序列的一種特殊情…

【數據結構與算法 | 二叉樹篇】二叉樹的前中后序遍歷(迭代版本)

1. 前言 前文我們實現了二叉樹前中后三種遍歷方式的遞歸版本&#xff0c;非常簡單. 接下來我們來實現一下其迭代版本. 2. 二叉樹的前序遍歷 (1). 題 給你二叉樹的根節點 root &#xff0c;返回它節點值的 前序 遍歷。 示例 1&#xff1a; 輸入&#xff1a;root [1,null,2…

語音技能云云接入通用平臺

Cloud-to-Cloud(云云接入) 前言 項目地址&#xff1a;https://github.com/LeYunone/cloud-to-cloud 配置說明&#xff1a;https://leyunone.com/github-project/voice-cloud-cloud-config.html 注&#xff1a;學習測試以及使用請拉取 master 分支&#xff0c;release 是開發…

python pip 安裝

如果您不確定pip的安裝路徑&#xff0c;可以通過以下命令來查詢&#xff1a; pip show pip 這個命令會顯示pip的詳細信息&#xff0c;其中包括pip安裝的路徑。如果您想修改pip的默認安裝路徑&#xff0c;可以使用pip的"--target"參數指定目標路徑&#xff0c;例如&a…

8.7k Star!Khoj:你的AI第二大腦、開源RAG Cop??ilot、平替 MS Copilot與ChatGPT

原文鏈接&#xff1a;&#xff08;更好排版、視頻播放、社群交流、最新AI開源項目、AI工具分享都在這個公眾號&#xff01;&#xff09; 8.7k Star&#xff01;Khoj&#xff1a;你的AI第二大腦、開源RAG Cop??ilot、平替 MS Copilot與ChatGPT &#x1f31f;你的AI第二大腦。…

zynq-7015啟動分析及裸機BootLoader編寫(未完待續)

使用lwip-tcp遠程對QSPI進行更新、QSPI FLASH啟動 W25Q128資料&#xff1a; W25Q128JV datasheet(1/78 Pages) WINBOND | 3V 128M-bit serial flash memory with dual/quad spi (alldatasheet.com) UG585資料&#xff1a; Zynq 7000 SoC Technical Reference Manual-UG585 翻譯…

【ARFoundation自學05】人臉追蹤(AR Face manager)實現

1. 修改攝像機朝向渲染方式-選中user 這個方式就會調用前置攝像頭 2 創建 AR Session、XR Origin&#xff0c;然后在XR Origin上面添加組件 注意&#xff1a;XR Origin 老版本仍然叫 AR Session Origin 接下來在XR Origin上面添加AR Face Manager組件&#xff0c;如下圖&am…

劇本殺市場仍在快速發展,劇本殺小程序成為了新的機遇

近年來&#xff0c;劇本殺一直是年輕人的娛樂游戲方式之一&#xff0c;劇本殺行業呈現出了井噴式發展的形勢&#xff0c;成為了當下爆火的娛樂方式。目前&#xff0c;劇本殺行業擁有了完善的劇本資源和呈現方式&#xff0c;發展前景非常大。 根據當下的數據顯示&#xff0c;劇…

NextJs 實現自定義點火操作

NextJs 實現自定義點火操作 前言實現自定義點火 前言 我希望在Nextjs 啟動的時候&#xff0c;能夠自定義實現一些項目的初始化邏輯&#xff0c;也可以說是一些點火操作&#xff0c;比如資源的加載&#xff0c;數據的初始化等操作。 實現自定義點火 我們可以在根目錄下創建一…

Android 開機動畫的啟動過程BootAnimation(基于Android10.0.0-r41)

文章目錄 Android 開機動畫的啟動過程BootAnimation(基于Android10.0.0-r41)1.開機動畫的啟動過程概述2.為什么設置了屬性之后就會播放&#xff1f; Android 開機動畫的啟動過程BootAnimation(基于Android10.0.0-r41) 1.開機動畫的啟動過程概述 下面就是BootAnimation的重要部…

移動app測試重要性體現在哪些方面?專業app測試報告獲取

移動app測試是指對手機應用進行各種測試和評估的過程&#xff0c;以確保應用的功能、性能和用戶體驗達到要求。在現代社會中&#xff0c;移動應用已經成為人們日常生活的一部分。無論是社交娛樂、購物支付還是工作學習&#xff0c;移動應用都發揮著不可替代的作用。因此&#x…

常微分方程 (ODE) 和 隨機微分方程 (SDE)

常微分方程&#xff08;Ordinary Differential Equations, ODE&#xff09;和隨機微分方程&#xff08;Stochastic Differential Equations, SDE&#xff09;是數學中描述系統動態行為的重要工具。它們有一些相似之處&#xff0c;但在處理隨機性方面存在顯著差異。 常微分方程…

Oracle數據庫面試題-5

81. 請解釋Oracle數據庫中的自動空間重新壓縮&#xff08;Automatic Space Recompression&#xff09;的概念。 Oracle 數據庫中的自動空間重新壓縮&#xff08;Automatic Space Recompression&#xff09; 自動空間重新壓縮是 Oracle 數據庫中的另一個重要特性&#xff0c;它…

Vue響應式系統分支切換與cleanup - 清除遺留的副作用函數

文章目錄 前言分支切換與cleanup分支切換的問題依賴集合的收集cleanup的實現完整的代碼展示 前言 本篇文章代碼思路來自 Vue3.0 源碼, 部分理解來源于霍春陽 《Vue.js設計與實現》這本書的理解, 感興趣的小伙伴可以自行購買閱讀。可以非常明確的感受到作者對 Vue 的深刻理解以及…

每天寫java到期末考試(6.6)-java文件輸入輸出流實驗

1、用字節流讀寫二進制文件 要求:用DataOutputStreamFileOutputStream類將1,2,…,100,這100個數字寫入到文件 d:\out1.bin里,然后再用DatalnputStreamFilelnputStream類將d:\out1.bin的內讀出來,并輸出到屏幕上。 用DataOutputStreamFileOutputStream寫入二進制數據時,直接調…