中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

公司微網(wǎng)站怎么建設(shè)廣州線上教學(xué)

公司微網(wǎng)站怎么建設(shè),廣州線上教學(xué),網(wǎng)站為什么改版,深圳做企業(yè)網(wǎng)站的公司目錄 前言 1.進(jìn)程間通信理論 2.使用管道進(jìn)行通信 3.管道的一些信息 4.應(yīng)用場(chǎng)景:進(jìn)程池(基于匿名管道) 5.命名管道 6.總結(jié) 前言 本篇我們開始學(xué)習(xí)linux進(jìn)程間通信相關(guān)的內(nèi)容,第一篇我們要介紹的是進(jìn)程間通信的理論概念以及匿…

目錄

前言

1.進(jìn)程間通信理論

2.使用管道進(jìn)行通信

3.管道的一些信息

4.應(yīng)用場(chǎng)景:進(jìn)程池(基于匿名管道)

5.命名管道

6.總結(jié)


前言

? 本篇我們開始學(xué)習(xí)linux進(jìn)程間通信相關(guān)的內(nèi)容,第一篇我們要介紹的是進(jìn)程間通信的理論概念以及匿名、命名管道通信的詳細(xì)操作,并且我們還會(huì)基于匿名管道實(shí)現(xiàn)一個(gè)簡(jiǎn)單的線程池,加油!!

1.進(jìn)程間通信理論

1.什么是通信

image-20250514164645153

進(jìn)程間通信也叫做IPC技術(shù)

image-20250524141716554

發(fā)展:從單機(jī)通信到網(wǎng)絡(luò)通信

如何理解通信的本質(zhì)問題:

1.操作系統(tǒng)需要直接或者間接給通信雙方的進(jìn)程提供 ”內(nèi)存空間“

2.要通信的進(jìn)程,必須看到一份公共的資源

通信前提:要先讓不同的進(jìn)程看到同一份資源【某一種“內(nèi)存”】(我們學(xué)通信實(shí)際上是學(xué)這個(gè))

不同的通信種類:

本質(zhì)就是:上面所說的資源,是操作系統(tǒng)的哪一個(gè)模塊提供的

2.為什么要有通信?

有時(shí)候我們是需要多進(jìn)程協(xié)同,然后去完成某種業(yè)務(wù)內(nèi)容比如: cat file | grep 'hello'

3.怎么辦?

進(jìn)程看到的同一份“資源”是由操作系統(tǒng)提供,操作系統(tǒng)需要設(shè)計(jì)統(tǒng)一的通信接口,這個(gè)接口要如何被調(diào)用就是我們的進(jìn)程間通信的方案,原則就是先統(tǒng)一標(biāo)準(zhǔn),后使用

進(jìn)程間通信的方案

采用標(biāo)準(zhǔn)做法:

POSIX —— 讓通信過程可以跨主機(jī)

System V —— 聚焦在本地通信

采用文件做法讓不同的進(jìn)程看到同一份資源:

1.管道——基于文件系統(tǒng)

a.匿名管道

b.命名管道

什么是管道

image-20250514190328695

匿名管道,不需要IO,不需要刷新到磁盤上,和磁盤甚至沒關(guān)系,為內(nèi)存級(jí)文件,沒有所謂的名稱

image-20250615213742529

兩進(jìn)程分別以讀和寫方式打開同一個(gè)文件,為了讓子進(jìn)程也能看到讀寫端

image-20250514205616028

一般而言,我們的管道只能用來進(jìn)行單向數(shù)據(jù)通信,所以需要分別把父子進(jìn)程不需要的fd關(guān)閉

匿名管道:目前能用來進(jìn)行父子進(jìn)程之間進(jìn)程間通信

2.使用管道進(jìn)行通信

管道是被操作系統(tǒng)單獨(dú)設(shè)計(jì)的,需要配上單獨(dú)的系統(tǒng)調(diào)用

管道函數(shù):pipe

其中的pipefd為輸出型參數(shù),用來存儲(chǔ)打開文件后返回的讀寫兩個(gè)文件描述符

  • 成功時(shí):返回 0,同時(shí)會(huì)通過傳入的整數(shù)數(shù)組參數(shù)(如 int pipefd[2])返回兩個(gè)文件描述符,pipefd[0] 用于從管道讀取數(shù)據(jù)(讀端),pipefd[1] 用于向管道寫入數(shù)據(jù)(寫端)

  • 失敗時(shí):返回 -1,并設(shè)置 errno 變量以標(biāo)識(shí)具體的錯(cuò)誤原因(如文件描述符用盡、參數(shù)地址不合法等)

image-20250515182817992

image-20250516152354886

[^] ?pipefd0是讀取(想象成嘴巴用來讀),pipefd1是寫入(想象成筆用來寫)?

我們可以看到創(chuàng)建pipe管道這個(gè)文件時(shí),pipe函數(shù)是不需要傳遞文件路徑的,因?yàn)樗莾?nèi)存級(jí)文件,壓根不需要文件路徑,也就是說也不需要文件名,所以叫做匿名管道

那沒有文件名,要怎么去保證兩個(gè)進(jìn)程打開的是同一個(gè)管道文件呢?答:子進(jìn)程繼承父進(jìn)程文件描述符表

各種 ‘printf’

前面幾種的區(qū)別是把內(nèi)容格式化到特定的文件或是字符串內(nèi),第一種printf就是格式化顯示到顯示器上

image-20250516185431273

3.管道的一些信息

管道的5種特性:

  1. 匿名管道只能用來進(jìn)行具有”血緣關(guān)系“的進(jìn)程進(jìn)行進(jìn)程間通信(通常是父子)

  2. 管道文件,自帶同步機(jī)制(后面多線程詳談)

  3. 管道是面向字節(jié)流

  4. 管道是單向通信的——屬于半雙工的一種特殊情況

    a. 任何一個(gè)時(shí)刻,一個(gè)發(fā),一個(gè)收——半雙工

    b. 任何一個(gè)時(shí)刻,可以同時(shí)發(fā)收——全雙工

  5. (管道)文件的生命周期是隨進(jìn)程的,進(jìn)程一旦結(jié)束,所打開的文件就被操作系統(tǒng)關(guān)閉

管道的4種通信情況:

  1. 寫慢,讀快——讀端就要阻塞(進(jìn)程),要等寫端

  2. 寫快,讀慢——寫端就要阻塞(進(jìn)程),要等讀端

    以上兩種情況是因?yàn)楣艿赖耐綑C(jī)制這一特性形成的

  3. 寫關(guān),繼續(xù)讀——read就會(huì)讀到返回值(\0也就是0),表示文件結(jié)尾,如果讓n=read(),那么n的值此時(shí)就為0

  4. 讀關(guān),繼續(xù)寫——寫端在寫入,沒有任何意義(os不會(huì)做沒有意義的事情),所以這種情況發(fā)生之后,操作系統(tǒng)會(huì)殺掉寫端進(jìn)程,然后發(fā)送異常信號(hào):13->SIGPIPE

image-20250525154025308

image-20250525154208760

管道的容量

image-20250525161000420

image-20250525160704947

[^] ?也就是65536/1024=64kb?

管道的寫入原子性

管道寫入的原子性是指:當(dāng)進(jìn)程向管道寫入數(shù)據(jù)時(shí),若數(shù)據(jù)量不超過 PIPE_BUF(如 Linux 中為 4096 字節(jié),POSIX 規(guī)定至少 512 字節(jié)),該寫入操作要么完全成功(數(shù)據(jù)全部寫入),要么完全失敗(數(shù)據(jù)未寫入),不會(huì)出現(xiàn)部分寫入的情況

image-20250525163105919

4.應(yīng)用場(chǎng)景:進(jìn)程池(基于匿名管道)

池化技術(shù)

可以減少我們創(chuàng)建對(duì)應(yīng)某種資源的成本,提高訪問時(shí)的效率

image-20250525164532521

如果父進(jìn)程把所有任務(wù)都分配給一個(gè)子進(jìn)程——負(fù)載不均衡

我們要雨露均沾地分配任務(wù)——負(fù)載均衡

幾種方式實(shí)現(xiàn)均衡

  1. 輪詢

  2. 隨機(jī)

  3. channel添加負(fù)載指標(biāo)

進(jìn)程池信道的建立

#pragma once
#include <iostream>
#include <cstdlib> //cstdlib->stdlib.h
#include <vector>
#include <unistd.h>
using namespace std;
?
//.hpp后綴可以使得方法實(shí)現(xiàn)和聲明在一個(gè)文件,這樣Main.cc在調(diào)用時(shí)只需要包含.hpp頭文件
?
// 進(jìn)程池
?
// 對(duì)(信道)管道進(jìn)行管理
// 先描述:描述管道信息
class channel
{
public:channel(int fd, pid_t id): _wfd(fd),_subid(id){// 使用to_string將fd和id都轉(zhuǎn)成字符加到后面作為名字一部分_name = "channel-" + to_string(_wfd) + "-" + to_string(_subid);}
?~channel() {}
?// 外部需要拿到channel內(nèi)部的信息,我們需要一些get方法int Fd() { return _wfd; }pid_t SubId() { return _subid; }string Name() { return _name; }
?
private:// 每個(gè)管道都需要有對(duì)應(yīng)的文件描述符int _wfd;// 還需要知道對(duì)應(yīng)的子進(jìn)程的idpid_t _subid;// 以及為了之后方便打印提示消息對(duì)應(yīng)管道的名字string _name;
};?
// 要?jiǎng)?chuàng)建多少個(gè)進(jìn)程池
const int gdefaultnum = 5;
?
// 再組織;管理信道(管道)的接口類,我們這里通過vector數(shù)據(jù)結(jié)構(gòu)來組織
class ChannelManager
{
public:ChannelManager() {}~ChannelManager() {}
?void Insert(int wfd, pid_t subid){// 構(gòu)建一個(gè)channel然后push到組織的vector數(shù)組中(先描述,再組織)// channel c(wfd, subid);//_channels.push_back(move(c)); //c為臨時(shí)對(duì)象,應(yīng)該使用右值引用減少拷貝// 或者也可以使用vector容器中提供的emplace_back方法// 直接調(diào)用內(nèi)部構(gòu)造函數(shù)幫我們創(chuàng)建一個(gè)對(duì)象在插入vector中_channels.emplace_back(wfd, subid);}
?// 打印_channels中各channel的信息的方法void PrintChannels(){for (auto &channel : _channels){cout << channel.Name() << endl;}}
?
private:// 通過vector來組織vector<channel> _channels;
};?
// 進(jìn)程池類
class ProcessPool
{
public:ProcessPool(int num): _process_num(num){}
?~ProcessPool() {}
?// 子進(jìn)程要做的工作void Work(int rfd){// 偽工作while (true){cout << "我的rfd是: " << rfd << endl;sleep(5);}}
?// 創(chuàng)建進(jìn)程池方法bool Create(){// 要?jiǎng)?chuàng)建process_num個(gè)進(jìn)程for (int i = 0; i < _process_num; i++){// 1. 創(chuàng)建管道int pipefd[2] = {0};int n = pipe(pipefd);if (n < 0){return false;}
?// 2. 創(chuàng)建子進(jìn)程// 子進(jìn)程讀,父進(jìn)程寫int subid = fork();if (subid < 0)return false;else if (subid == 0){// 子進(jìn)程// 3. 關(guān)閉寫端close(pipefd[1]);Work(pipefd[0]); // 子進(jìn)程要做的讀端相關(guān)工作close(pipefd[0]);
?// 執(zhí)行完直接退出// 不會(huì)干擾for循環(huán),只有父進(jìn)程會(huì)一直循環(huán)創(chuàng)建執(zhí)行循環(huán)內(nèi)代碼exit(0);}else{// 父進(jìn)程// 3. 關(guān)閉讀端close(pipefd[0]);// 需要在ChannelManager內(nèi)部把我們的fd和subid信息傳入創(chuàng)建的channel中// 再由ChannelManager把創(chuàng)建好的channel插入到數(shù)組中// 所以在ChannelManager類中需要Insert方法來完成上述操作// 其中我們父進(jìn)程對(duì)應(yīng)的fd文件描述符是寫端:pipefd[1]_cn.Insert(pipefd[1], subid);}}// 創(chuàng)建成功return true;}
?// Debug方法中查看每個(gè)channel信道(管道)的信息void Debug(){// 調(diào)用ChannelManager中的PrintChannels方法_cn.PrintChannels();}
?
private:// 進(jìn)程池類內(nèi)部需要包含我們的通信信道// 所以我們通過管理通信信道的類創(chuàng)建一個(gè)對(duì)象在進(jìn)程池內(nèi)部ChannelManager _cn;// 要?jiǎng)?chuàng)建的進(jìn)程池對(duì)應(yīng)的進(jìn)程的個(gè)數(shù),這樣就能確定管道的個(gè)數(shù)int _process_num;
};

image-20250527215423842

image-20250525203708327

采用輪詢的方式使得負(fù)載平衡

image-20250526130910735

進(jìn)程池相關(guān)完整源代碼可以看:ProcessPool?

5.命名管道

匿名管道只能用來進(jìn)行具有血緣關(guān)系的進(jìn)程進(jìn)行進(jìn)程間通信(常用于父子進(jìn)程)

如果兩個(gè)進(jìn)程不相關(guān),該如何進(jìn)行通信呢?

image-20250527214338068

image-20250527213403568

通過上圖其實(shí)我們就已經(jīng)通過打開同一路徑下的同一個(gè)文件來做到讓不同的進(jìn)程看到了同一份資源(進(jìn)程間通信的前提),而因?yàn)槲募新窂?#xff08;使得這個(gè)路徑下文件具有唯一性,通過路徑來區(qū)分)、有名字——所以這種通信的方式叫做——命名管道!

我們一般文件是要刷新到磁盤的,我們的命名管道這種作為通信的文件是不能被刷新的,所以命名管道需要一種特殊的文件——管道文件(只會(huì)被打開,不需要刷新)

我們通過mkfifo命令來創(chuàng)建管道文件,也就是命名管道

image-20250527215829686

image-20250527220213397

echo和cat在執(zhí)行時(shí)就是進(jìn)程(shell運(yùn)行原理,不管是不是內(nèi)建命令,它都是進(jìn)程)

image-20250527221036033

所以上圖中我們就利用命名管道完成了一次進(jìn)程間通信,echo將"hello fifo"重定向輸入,然后cat重定向輸出從fifo中顯示內(nèi)容到終端上

我們可以通過unlink命令來刪除管道文件

image-20250528194032982

image-20250528194117756

我們?cè)诖a上可以通過mkfifo接口來創(chuàng)建管道文件

image-20250528112541945

記住這里的第一個(gè)參數(shù)是c語言格式的字符,如果用string對(duì)象,得調(diào)用c_str()

路徑加名字就構(gòu)成我們要構(gòu)建的命名管道了

string fifoname = _path + "/" + _name;

int n = mkfifo(fifoname.c_str(), 0666);

image-20250527222737970

[^] ?上圖內(nèi)容不理解沒關(guān)系,我們?cè)诰W(wǎng)絡(luò)部分才會(huì)進(jìn)一步去理解?

同樣的,我們?cè)诖a上可以用unlink函數(shù)來關(guān)閉管道文件

image-20250528164710437

image-20250528164956509

[^] ?關(guān)閉成功返回0,失敗返回-1,和mkfifo創(chuàng)建返回邏輯是一樣的?

簡(jiǎn)單用命名管道通信代碼:

comm.hpp

#pragma once
?
#define FIFO_FILE "fifo"

server.cc

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <fcntl.h>
#include "comm.hpp"
using namespace std;
?
int main()
{umask(0);// 新建管道int n = mkfifo(FIFO_FILE, 0666);if (n != 0){cerr << "mkdir fifo error" << endl;return 1;}cout << "mkfifo success" << endl;
?// 以讀打開管道文件// write方?jīng)]有執(zhí)行open時(shí),read方就要在open內(nèi)部阻塞// 直到有人把管道文件打開了,open才會(huì)返回int fd = open(FIFO_FILE, O_RDONLY);if (fd < 0){cerr << "open fifo error" << endl;return 2;}cout << "open fifo success" << endl;
?// 正常讀取char buffer[1024];while (true){int number = read(fd, buffer, sizeof(buffer) - 1);if (number > 0){// 我們把讀到內(nèi)容當(dāng)成字符串,所以得在n位置加上\0buffer[number] = '\0';cout << "client say: " << buffer << endl;}else if (number == 0){cout << "client quit! me too " << number << endl;break;}else{cerr << "read error" << endl;break;}}
?// 關(guān)閉管道文件close(fd);
?// 刪除管道文件n = unlink(FIFO_FILE);if (n == 0){cout << "remove fifo success" << endl;}else{cout << "remove fifo failed" << endl;}
?return 0;
}

client.cc

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <fcntl.h>
#include "comm.hpp"
using namespace std;
?
int main()
{// client端不需要?jiǎng)?chuàng)建管道文件了,因?yàn)槲覀冊(cè)趕erver端已經(jīng)創(chuàng)建好了int fd = open(FIFO_FILE, O_WRONLY);// 剩下的都是文件操作了if (fd < 0){cerr << "open fifo error" << endl;return 2;}
?// 寫入操作string message;int cnt = 1;pid_t id = getpid();while (true){cout << "Please Enter# ";getline(cin, message);message += (",message number: " + to_string(cnt++) + ",[" + to_string(id) + "]");
?// c_str()用于將string對(duì)象轉(zhuǎn)換為 C 風(fēng)格的字符串(即以空字符\0結(jié)尾的字符數(shù)組)int n = write(fd, message.c_str(), message.size());if (n > 0){}}
?close(fd);
?return 0;
}

我們需要先執(zhí)行server編譯后的可執(zhí)行程序,來創(chuàng)建命名管道,而后它會(huì)阻塞在open那塊,因?yàn)槊艿佬枰獌蓚€(gè)進(jìn)程來同時(shí)打開(我們這里write方?jīng)]有執(zhí)行open時(shí),read方就要在open內(nèi)部阻塞,直到有人把管道文件打開了,open才會(huì)返回),所以接下來我們需要在另一個(gè)終端上執(zhí)行client編譯后的可執(zhí)行程序,就達(dá)到了用命名管道實(shí)現(xiàn)進(jìn)程間通信(從客戶端進(jìn)程向服務(wù)端進(jìn)程發(fā)送消息)的簡(jiǎn)單效果

image-20250528192036856

image-20250528192053076

當(dāng)我們關(guān)閉寫端client時(shí),讀端的number就為0了,然后也跟著退出后刪除管道文件

image-20250528194944842

6.總結(jié)

命名管道和匿名管道的區(qū)別

image-20250527222510087

其他的特性是完全和匿名管道一樣的,只有一點(diǎn)不同,那就是命名管道可以用來進(jìn)行讓不相關(guān)進(jìn)程進(jìn)行進(jìn)程間通信,命名管道也可以用來實(shí)現(xiàn)文件的拷貝

http://www.risenshineclean.com/news/59419.html

相關(guān)文章:

  • 動(dòng)易網(wǎng)站后臺(tái)密碼破解寧夏百度推廣代理商
  • 航達(dá)建設(shè)網(wǎng)站上海優(yōu)質(zhì)網(wǎng)站seo有哪些
  • 有沒有什么做統(tǒng)計(jì)的網(wǎng)站網(wǎng)絡(luò)營銷比較好的企業(yè)
  • 如何解決網(wǎng)站只收錄首頁的一些辦法小程序制作
  • cms網(wǎng)站地圖模板東莞搜索引擎推廣
  • 開淘寶店和做網(wǎng)站有什么區(qū)別福鼎網(wǎng)站優(yōu)化公司
  • 直接打域名訪問網(wǎng)站關(guān)鍵詞推廣工具
  • 網(wǎng)站制作設(shè)及的技術(shù)產(chǎn)品營銷策劃方案3000字
  • 廣州定制網(wǎng)站建設(shè)廣東seo網(wǎng)站推廣代運(yùn)營
  • 成都網(wǎng)站開發(fā)哪個(gè)好深圳seo優(yōu)化排名
  • 嵌入式培訓(xùn)班多少錢seo優(yōu)化推廣軟件
  • 企業(yè)網(wǎng)站備案 名稱沈陽seo博客
  • 伊通縣建設(shè)局網(wǎng)站常德政府網(wǎng)站
  • 學(xué)校英語網(wǎng)站欄目名稱域名備案
  • WordPress漢化卡片式主題長(zhǎng)嶺網(wǎng)站優(yōu)化公司
  • 做直播網(wǎng)站需要什么環(huán)球軍事網(wǎng)
  • 網(wǎng)站建設(shè)好之后怎么自己推廣免費(fèi)推廣引流平臺(tái)有哪些
  • 服務(wù)器做網(wǎng)站需安裝哪些軟件佛山網(wǎng)站建設(shè)排名
  • 外包做網(wǎng)站賺錢么app注冊(cè)推廣拉人
  • 濟(jì)南做網(wǎng)站哪家便宜seo項(xiàng)目經(jīng)理
  • 網(wǎng)站怎么添加js廣告位免費(fèi)seo搜索優(yōu)化
  • 常德論壇網(wǎng)站看廣告賺錢
  • 住房和城鄉(xiāng)建設(shè)部網(wǎng)站安廣東省淘寶指數(shù)官網(wǎng)
  • 優(yōu)化網(wǎng)站用軟件好嗎山東一級(jí)造價(jià)師
  • 建設(shè)摩托車官網(wǎng)旗艦店寶雞seo排名
  • 甘肅省蘭州市建設(shè)廳網(wǎng)站硬件優(yōu)化大師
  • 用dreamever如何建設(shè)網(wǎng)站百度指數(shù)數(shù)據(jù)官網(wǎng)
  • 什么系統(tǒng)做網(wǎng)站好2022年最新新聞播報(bào)稿件
  • 濰坊做網(wǎng)站個(gè)人工作室cms自助建站系統(tǒng)
  • 個(gè)人網(wǎng)站建設(shè)工作室深圳網(wǎng)站設(shè)計(jì)十年樂云seo