linux高級編程:線程(二)、進程間的通信方式

線程:

回顧線程(一):

1.線程間通信問題

? ?線程間共享同一個資源(臨界資源)

? ?互斥:

? ? ? ? 排他性訪問

? ? ? ? linux系統 -- 提供了Posix標準的函數庫?-- 互斥量(互斥鎖)

? ?原子操作:---

? ?機制:

? ? ? ? 加鎖 -- 解鎖

? ? ? ? 鎖 --- 操作系統 --- (實現的機制,需要操作系統來

? ? ? ? | - 加鎖 -- 用戶態 -- 切換到(耗時) -- 內核態 -- 獲得了 -- 內核態 -- 用戶態 -- 解鎖 |

? ?函數:

? ? ? ? pthread_mutex_t mutex;

? ? ? ? pthread_mutex_init();

? ? ? ? pthread_mutex_lock();

? ? ? ? pthread_mutex_trylock();? ? //? 嘗試獲得鎖,若沒獲得則返回非0值。

????????????????

? ? ? ? pthread_mutex_unlock();

? ? ? ? pthread_mutex_destroy();

線程的同步:

? ? ??

????????同步 ==》有 一定先后順序的 對資源的排他性訪問。

? ? ? ? 要同步的原因:互斥鎖可以控制排他訪問但沒有次序。
?? ?
? ? ? ? 信號量 --- 實現線程間的同步.
?? ?
? ? ? ? 來源? 生活 --- 交通信號燈

信號量的分類:


????????1、無名信號量 ==》線程間通信
????????2、有名信號量 ==》進程間通信

同步機制:

? ? ? ? 信號量(個數) --- 反映的是資源的數量

? ? ? ? 考慮的時候,站在使用這的角度考慮

? ? ? ? 站在a的角度考慮。。。。。。

框架:

????????1. 信號量的定義? ? ? ?sem_t ?sem? //造了一類資源
????????2. 信號量的初始化 ? sem_init?
????????3. 信號量的PV操作 (核心) sem_wait()/ sem_post()
????????4. 信號量的銷毀。 ? sem_destroy

??

信號量函數:

1、定義

sem_t 名字;

2、初始化

int sem_init(sem_t *sem, int pshared, unsigned int value);

????????功能:

????????????????將已經定義好的信號量賦值。

????????參數:

? ? ? ? ? ? ? ? @sem 要初始化的信號量

? ? ? ? ? ? ? ? @pshared

????????????????????????pshared = 0 ;表示線程間使用信號量(一般填這個)

????????????????????????!=0 ;表示進程間使用信號量

? ? ? ? ? ? ? ? @value:

????????????????????????信號量的初始值,一般無名信號量(一開始的資源的個數)

????????????????????????都是二值信號量,0 1

????????????????????????0 表示紅燈,進程暫停阻塞

????????????????????????1 表示綠燈,進程可以通過執行

????????????????????????也可以是多個,變成計數信號量

????????????????返回值:

????????????????????????成功 0,失敗 -1;

3、PV操作

int sem_wait(sem_t *sem); //p操作

????????功能:

????????????????判斷當前sem信號量是否有資源可用。

????????????????如果sem有資源(==1),則申請該資源,程序繼續運行

????????????????如果sem沒有資源(==0),則線程阻塞等待,一旦有資源

????????????????則自動申請資源并繼續運行程序。

????????????????消耗了這個sem,就沒有了

?????????????注意:sem 申請資源后會自動執行 sem = sem - 1;

????????參數:

? ? ? ? ? ? ? ? @sem 要判斷的信號量資源

????????????????返回值:

????????????????????????成功 0 ,失敗 -1

int sem_post(sem_t *sem); //V操作

????????功能:

????????????????函數可以將指定的sem信號量資源釋放

????????????????并默認執行,sem = sem+1;

????????????????線程在該函數上不會阻塞。

????????????????產生了這個sem就有了,可以由wait(sem)接受去消耗

????????????????參數:

? ? ? ? ? ? ? ? @sem 要釋放資源的信號量

????????????????返回值:

????????????????????????成功 0,失敗 -1;

4、銷毀

int sem_destroy(sem_t *sem);

練習:? ?hello world
#include<stdio.h>
#include<semaphore.h>
#include<errno.h>
#include<pthread.h>
#include<stdlib.h>sem_t sem_h;
sem_t sem_w;void *do_hello(void *arg)
{while(1)	{sem_wait(&sem_h);printf("hello ");sem_post(&sem_w);}return NULL;
}void *do_world(void *arg)
{while(1)	{sem_wait(&sem_w);printf("world\n");sem_post(&sem_h);}return NULL;}
typedef void *(*threadF_t)(void *);
int main(int argc, const char *argv[])
{int i;pthread_t tid[i];threadF_t pFunc[2] = {do_hello,do_world};sem_init(&sem_h,0,1);sem_init(&sem_w,0,0);for(i = 0;i < 2;++i){int ret = pthread_create(&tid[i],NULL,pFunc[i],NULL);if(ret != 0){errno = ret;perror("pthread_create fail");exit(EXIT_FAILURE);}}sem_destroy(&sem_h);sem_destroy(&sem_w);pthread_detach(tid[0]);pthread_detach(tid[1]);printf("---main----exit\n");pthread_exit(NULL);return 0;
}

進程間的通信方式:

三大類:

1.同主機 ? ---- 基于內存的?
? ???????

?古老的通信方式?
? ? ????????????????//管道 ?----?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?無名管道 ?
?? ? ????????????????????????有名管道
? ????????????????? //信號 ?
?? ?
? ????????IPC對象通信(改進)
? ? ?????????????????消息隊列(用的相對少,這里不討論)
? ? ?????????????????共享內存(*) //最高效?
? ? ?????????????????信號量集() //信號量 ?

?
2.? ? ?

????????//不同主機 、多臺主機
????????? socket //網絡部分?
??
????????//同一主機
? ? ? ? 2.1、古老的通信方式
?? ??? ?????????管道:
?? ??? ? ? ????????????????無名管道 ?
?? ??? ? ? ????????????????有名管道 ?
?? ??? ????????????????????信號

? ? ? ? 2.2、IPC對象通信 system v ? ?BSD ? ? suse fedora ? kernel.org
?? ??? ?????????消息隊列(用的相對少,這里不討論)
?? ??? ?????????共享內存(*) //最高效?
?? ??? ?????????信號量集() //信號量 ?


????????//不同主機?


3、socket通信

?? ??? ?網絡通信

?

1、pipe? 無名管道

使用框架:

????????????????創建管道 ==》讀寫管道 ==》關閉管道

1、無名管道 ===》管道的特例 ===>pipe函數
?? ?特性:
?? ?????????1.1 ?親緣關系進程使用
?? ?????????1.2 ?有固定的讀寫端

? ?

流程:
?? ?創建并打開管道: pipe函數
?? ?

函數:

? ? #include <unistd.h>
?? ?int pipe(int pipefd[2]);
?? ?int pipe(int *pipefd);
?? ?int fd[2];
?? ?????????功能:創建并打開一個無名管道
?? ?????????參數:? @pipefd[0] ==>無名管道的固定讀端//0 -- 標準輸入
?? ??? ????????????????? @pipefd[1] ==>無名管道的固定寫端//1 -- 標準輸出?
?? ?????????返回值: 成功 0
?? ??? ??? ?????????????????失敗 -1;

注意事項:

?????????1、無名管道的架設應該在fork之前進行。??

關閉管道: close();

練習:父進程輸入、子進程打印

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <sys/wait.h>int main(int argc, const char *argv[])
{int fd[2];if(pipe(fd) < 0){perror("pipe fail");return -1;}char buf[100] = {0};int ret = 0;pid_t pid = fork();while(1){if(pid < 0){perror("fork fail");return -1;}else if(pid > 0){close(fd[0]);printf(">");fflush(stdout);ret = read(0,buf,sizeof(buf));buf[ret] = '\0';write(fd[1],buf,strlen(buf) + 1);if(strncmp(buf,"quit",4) == 0){wait(NULL);close(fd[1]);return 0;}}else if(pid == 0){close(fd[1]);ret = read(fd[0],buf,sizeof(buf));printf("date = %s\n",buf);if(strncmp(buf,"quit",4) == 0){close(fd[0]);exit(0);}}}return 0;
}

管道的讀寫規則:
? ?

? ? 1.讀端存在,寫管道
? ? ? ? ?管道空:可以寫數據
? ? ? ? ?管道滿:會造成-->寫阻塞?
?? ? ?
? ? 2.讀端不存在,寫管道
? ? ? ? ?系統會給進程發一個信號SIGPIPE(管道破裂)

? ? 3.寫端存在,讀管道
? ? ? ? ?管道空,讀不到數據,
? ? ? ? ?這時會造成讀操作阻塞

? ? 4.寫端不存在,讀管道?
? ? ? ? ?如果管道中有數據,則讀取這些數據!
? ? ? ? ?如果沒有數據,讀操作不阻塞,立即返回!

2、fifo有名管道

有名管道===》fifo ==》有文件名稱的管道。
?? ??? ??? ??? ??? ? ?????????????????????????????????????????????????文件系統中可見

框架:

?? ?(1).創建有名管道 -- 類似 文件 (管道文件)?
?? ?(2).打開有名管道 -- open?
?? ?(3).讀寫管道 ? ? -- read/write?
?? ?(4).關閉管道 ?==》卸載有名管道 //close??

1、創建:mkfifo? ? ?//創建了一個有名管道

#include <sys/types.h>
#include <sys/stat.h>
?remove();

int mkfifo(const char *pathname, mode_t mode);

????????功能:
? ? ? ????????????????在指定的pathname路徑+名稱下創建一個權限為
? ? ? ????????????????mode的有名管道文件。
????????參數:@pathname要創建的有名管道路徑+名稱
?? ? ?????????????????mode ?8進制文件權限。
????????返回值:? 成功 0
?? ??? ?????????????????失敗 ?-1;

2、打開有名管道 open

注意:該函數使用的時候要注意打開方式,
?? ?因為管道是半雙工模式,所有打開方式直接決定


?? ?當前進程的讀寫方式。
?? ?一般只有如下方式:
?? ?int fd-read = open("./fifo",O_RDONLY); ==>fd 是固定讀端? ? //阻塞,只有雙方以對應的方式打開的時候才會
?? ?int fd-write = open("./fifo",O_WRONLY); ==>fd 是固定寫端? ?
?? ?不能是 O_RDWR 方式打開文件。
?? ?不能有 O_CREAT 選項,因為創建管道有指定的mkfifo函數
?? ?
?? ?有名管道打開:
?? ?注意,
?? ?如果一端是以只讀,或者只寫方式打開的。
?? ?程序會阻塞,
?? ?阻塞在打開操作。
?? ?直到另一端,以只寫或只讀方式打開。
? ? A.c --- 只讀?
?? ?B.c --- 只寫?

練習:實現雙向通信:

? ? ? ? 打開兩個有名通道文件

// a
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>int main(int argc, const char *argv[])
{if (mkfifo("a_2_b",0666) < 0 && errno != EEXIST){perror("mkfifo fail");return -1;}if (mkfifo("b_2_a",0666) < 0 && errno != EEXIST){perror("mkfifo fail");return -1;}int fd_w = open("a_2_b",O_WRONLY);if (fd_w< 0){perror("open fail");return -1;}int fd_r = open("b_2_a",O_RDONLY);if (fd_r< 0){perror("open fail");return -1;}pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}char buf[1024] = {0};if (pid > 0){while (1){printf(">");fflush(stdout);fgets(buf,sizeof(buf),stdin);write(fd_w,buf,strlen(buf)+1);if (strncmp(buf,"quit",4) == 0){close(fd_w);close(fd_r);}}}else if (pid == 0){while (1){printf("<");int ret = read(fd_r,buf,sizeof(buf));printf("ret = %d: %s\n",ret,buf);}}return 0;
}// b
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>int main(int argc, const char *argv[])
{if (mkfifo("a_2_b",0666) < 0 && errno != EEXIST){perror("mkfifo fail");return -1;}if (mkfifo("b_2_a",0666) < 0 && errno != EEXIST){perror("mkfifo fail");return -1;}int fd_r = open("a_2_b",O_RDONLY);if (fd_r< 0){perror("open fail");return -1;}int fd_w = open("b_2_a",O_WRONLY);if (fd_w< 0){perror("open fail");return -1;}pid_t pid = fork();if (pid < 0){perror("fork fail");return -1;}char buf[1024] = {0};if (pid > 0){while (1){printf(">");fflush(stdout);fgets(buf,sizeof(buf),stdin);write(fd_w,buf,strlen(buf)+1);}}else if (pid == 0){while (1){printf("<");int ret = read(fd_r,buf,sizeof(buf));printf("ret = %d: %s\n",ret,buf);if (strncmp(buf,"quit",4) == 0){close(fd_w);close(fd_r);}}}return 0;
}

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

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

相關文章

精通Matplotlib:從入門到精通的繪圖指南

在本篇文章中&#xff0c;我們將深入探索Matplotlib庫&#xff0c;這是一個強大的Python繪圖庫&#xff0c;廣泛用于數據可視化。Matplotlib讓我們能夠以簡單而直觀的方式創建各種靜態、動態和交互式的圖表。無論你是數據分析師、科研人員&#xff0c;還是任何需要數據可視化的…

用Redis如何實現延遲隊列?

在Redis中實現延遲隊列可以利用有序集合&#xff08;Sorted Set&#xff09;和定時任務的方式。下面是一個基本的實現思路&#xff1a; 添加延遲任務&#xff1a; 將任務信息作為一個字符串存儲在Redis中&#xff0c;同時將其對應的執行時間作為分數(score)存儲在有序集合中。使…

Bililive-go 實現直播自動監控錄制

前言 最近有直播錄制的需求&#xff0c;但是自己手動錄制太麻煩繁瑣&#xff0c;于是用了開源項目Bililive-go進行全自動監控錄制&#xff0c;目前這個項目已經有3K stars了 部署 為了方便我使用了docker compose 部署 version: 3.8 services:bililive:image: chigusa/bilil…

win環境nginx實戰配置詳解

項目中經常使用nginx做負載均衡&#xff0c;接口路由、文件、文檔的上傳及下載、視頻的代理播放等等&#xff0c;都離不開nginx的支持&#xff0c;今天我們分享一下其個使用場景。 1、配置文件 nd-nginx.conf 全局配置 #全局配置端&#xff0c;對全局生效&#xff0c;主要設置…

leetcode-字符串相加

415. 字符串相加 題目中已經說明不能使用庫函數直接將輸入的字符串轉換為整數。這就需要我們自己實現大數加法的邏輯&#xff0c;我們可以從兩個字符串的最后一位開始&#xff0c;逐位相加&#xff0c;同時記錄進位。如果某一位相加的結果超過10&#xff0c;那么需要向前進位。…

javascript實現的星座查詢

今天在這個網站http://xzxys.wiicha.com/看到查詢星座幸運色的效果&#xff0c;想研究一下代碼&#xff0c;結果右鍵禁用。后來參考了一下別人的代碼&#xff0c;琢磨著先實現了一下星座查詢的功能&#xff0c;輸入月份和日期四位數后&#xff0c;可以查詢屬于哪個星座&#xf…

群體風暴之錘(War3地圖編輯器)

文章目錄 0、大致原理1、創建隱形單位2、新事件開端3、環境→新條件4、動作4.1、單位組4.1.1、圓范圍內單位4.1.2、指定條件 4.2、對單位組內的所有單位釋放風暴之錘 0、大致原理 真MK向目標點釋放風暴之錘時選定&#xff08;以技能釋放點為圓心&#xff0c;設定半徑&#xff0…

Python編程語言常用的包管理工具介紹

conda是一個開源的包管理器和環境管理器&#xff0c;用于安裝、運行和更新包和它們的依賴項。conda可以用于Python編程語言&#xff0c;但它也支持其他編程語言。conda的主要特點是它能夠在不同的環境中管理不同的包集合&#xff0c;這使得它非常適合于數據科學和機器學習項目&…

洛谷 P1439 最長公共子序列

題目描述 給出 1,2,…,n 的兩個排列 P1? 和 P2? &#xff0c;求它們的最長公共子序列。 輸入格式 第一行是一個數 n。 接下來兩行&#xff0c;每行為 n 個數&#xff0c;為自然數 1,2,…,n 的一個排列。 輸出格式 一個數&#xff0c;即最長公共子序列的長度。 輸入輸出…

詳解算法的時間復雜度和空間復雜度!

目錄 ?編輯 1. 算法效率 2. 時間復雜度 2.1 時間復雜度的概念 2.2 大O的表示漸進法 2.3 一個栗子 3. 空間復雜度 4. 常見復雜度對比 5. 完結散花 ??????? 悟已往之不諫&#xff0c;知來者猶可追 創作不易&#xff0c;寶子們&#xff01;如果這篇文章對你們有…

Flex布局

Flex布局是一種用于創建靈活且自適應的布局模型&#xff0c;它使得元素能夠更好地響應不同的屏幕尺寸和設備。Flex布局基于容器和項目的概念&#xff0c;通過設置容器的屬性來控制項目的布局和對齊方式。 Flex布局的關鍵概念包括&#xff1a; 父容器&#xff08;Flex容器&…

Git實戰(3)之merge與rebase區別

1,采用merge和rebase后,git log的區別,merge命令不會保留merge的分支的commit 2,處理沖突的方式: (一股腦)使用merge命令合并分支,解決完沖突,執行git add .和 git commit -mfix conflict。這個時候會產生一個commit。(交互式)使用rebase命令合并分支,解決完沖突,…

一種求最大最小值的方法(C語言)

作者在做項目時需要分析大量數據&#xff0c;其中需要用到最大值最小值的求解。這里分享一種簡單好用的方法&#xff0c;并避免在代碼中出現過多的for循環。 這個方法用到了qsort函數。 首先我們需要定義一個比較函數用來比較2個值的大小并通過返回值來表示比較的結果。 int…

STM32標準庫開發——FLASH閃存

FLASH介紹 一般來說&#xff0c;宣傳的FLASH的大小只是說程序存儲器的大小&#xff0c;不包括系統存儲器以及選項字節這倆個部分 IAP是內置在boot loader中的一道程序&#xff0c;可以用于輔助下載&#xff0c;用戶可以通過有線通信協議或者無線協議實現對程序的更新升級。 FLA…

如何使用grafana 下JSON API訪問展示接口數據

一.新增connection 點擊左側菜單欄&#xff0c;選擇Add new connection 下載安裝即可。 二. 增加對應url和參數 1. 添加新的數據源 2. 配置對應url 3.新建儀表盤和添加接口url和參數等

LeetCode每日一題之 移動0

前言&#xff1a; 我的每日一題專欄正式開始更新&#xff0c;我會分享關于我在LeetCode上刷題時的經驗&#xff0c;將經典題型拿出來詳細講解&#xff0c;來提升自己及大家的算法能力&#xff0c;希望這篇博客對大家有幫助。 題目介紹&#xff1a; 題目鏈接&#xff1a;. - …

SpringBoot+aop實現主從數據庫的讀寫分離

讀寫分離的作用是為了緩解寫庫&#xff0c;也就是主庫的壓力&#xff0c;但一定要基于數據一致性的原則&#xff0c;就是保證主從庫之間的數據一定要一致。如果一個方法涉及到寫的邏輯&#xff0c;那么該方法里所有的數據庫操作都要走主庫。 一、環境部署 數據庫&#xff1a;…

深入了解Java虛擬機(JVM)

Java虛擬機&#xff08;JVM&#xff09;是Java程序運行的核心組件&#xff0c;它負責解釋執行Java字節碼&#xff0c;并在各種平臺上執行。JVM的設計使得Java具有跨平臺性&#xff0c;開發人員只需編寫一次代碼&#xff0c;就可以在任何支持Java的系統上運行。我們剛開始學習Ja…

【leetcode】用隊列實現棧

大家好&#xff0c;我是蘇貝&#xff0c;本篇博客帶大家刷題&#xff0c;如果你覺得我寫的還不錯的話&#xff0c;可以給我一個贊&#x1f44d;嗎&#xff0c;感謝?? 點擊查看題目 思路: 在做此題之前&#xff0c;我們先要實現隊列&#xff0c;這在上個博客中已經寫過&#…

學習人工智能的方法及方向!

目錄 一、第一部分&#xff1a;了解人工智能 二、人工智能學習路線圖 三、職業規劃 四、未來展望 五、總結 在這個信息爆炸的時代&#xff0c;想要系統性地學習人工智能&#xff08;AI&#xff09;并找到對應方向的工作&#xff0c;你需要一個明確的學習路徑和職業規劃。本…