欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報邀請碼778899分享:算法 匿名管道 Linux

柚子快報邀請碼778899分享:算法 匿名管道 Linux

http://yzkb.51969.com/

管道

首先自己要用用戶層緩沖區(qū),還得把用戶層緩沖區(qū)拷貝到管道里,(從鍵盤里輸入數(shù)據(jù)到用戶層緩沖區(qū)里面),然后用戶層緩沖區(qū)通過系統(tǒng)調(diào)用(write)寫到管道里,然后再通過read系統(tǒng)調(diào)用,被對方(讀端)讀取,就要從管道拷貝到讀端,然后再顯示到顯示器上。

pipe創(chuàng)建一個管道

pipe的介紹

1完成這件事:

看圖分析

運行結(jié)果

#include

#include

using namespace std;

int main()

{

//創(chuàng)建管道

//先創(chuàng)建一個pipefd數(shù)組

int pipefd[2];

//用n接受一下,判斷是否成功

int n = pipe(pipefd);

if(n<0) return 1;//創(chuàng)建失敗了

//創(chuàng)建成功

//測試一下文件描述符是3和4

cout<<"pipefd[0]:"<

return 0;

}

2完成這件事:

創(chuàng)建一個子進程

pid_t id = fork();

if(id < 0)return 2;//創(chuàng)建失敗

if(id == 0)//創(chuàng)建成功

{

//子進程

}

//父進程

讓子進程寫入,父進程讀取

要想讓子進程進程寫,就需要在進程中關(guān)閉讀端

if(id == 0)//創(chuàng)建成功

{

//子進程

close(pipefd[0]);

}

同理

//父進程

close(pipefd[1]);

都用完結(jié)束后,可以都關(guān)掉

if(id == 0)//創(chuàng)建成功

{

//子進程

close(pipefd[0]);

//.....

close(pipefd[1]);

}

//父進程

close(pipefd[1]);

//.....

close(pipefd[0]);

IPC code,寫通信代碼

3這件事也完成了:

結(jié)構(gòu)就有了

然后在pipefd[1]這個管道里寫,定義一個Writer函數(shù)

if(id == 0)//創(chuàng)建成功

{

//子進程

close(pipefd[0]);

//.....IPC code,寫通信代碼

//在pipefd[1]這個管道里寫

Writer(pipefd[1]);

close(pipefd[1]);

exit(0);//正常退出

}

同理父進程的????????

//父進程

close(pipefd[1]);

//.....IPC code,寫通信代碼

//在pipefd[0]這個管道里寫

Reader(pipefd[0]);

close(pipefd[0]);

//子進程

void Writer(int wfd)

{

}

//父進程

void Reader(int rfd)

{

}

Writer

//子進程

void Writer(int wfd)

{

string s = "hello,I am child";

pid_t self = getpid();

int number = 0;

char buffer[10];

while(true)

{

buffer[0] = 0;//字符串清空,只是為了提醒閱讀代碼的人,我把這個數(shù)組當字符串了

}

}

用到snprintf 介紹

將s和self和number放進buffer

char buffer[100];

while(true)

{

buffer[0] = 0;//字符串清空,只是為了提醒閱讀代碼的人,我把這個數(shù)組當字符串了

snprintf(buffer,sizeof(buffer),"%s pid:%d\n",s.c_str(),self);

cout<< buffer <

sleep(1);

};

用cout打印測試一下,打印成功說明寫入buffer成功了

等待進程少不了,子進程exit后需要回收

//父進程

close(pipefd[1]);

//.....IPC code,寫通信代碼

//在pipefd[0]這個管道里寫

Reader(pipefd[0]);

//等待進程缺少不了

pid_t rid = waitpid(id,nullptr,0);

if(rid < 0) return 3;//等待失敗了

close(pipefd[0]);

如何把消息發(fā)送/寫入給父進程

用到了write

用write寫入管道(管道也是文件),用strlen,不用+1,不用管\0,因為C語言規(guī)定\0結(jié)尾,和文件沒有關(guān)系,wfd寫入管道

//子進程

void Writer(int wfd)

{

string s = "hello,I am child";

pid_t self = getpid();

int number = 0;

char buffer[100];

while(true)

{

buffer[0] = 0;//字符串清空,只是為了提醒閱讀代碼的人,我把這個數(shù)組當字符串了

snprintf(buffer,sizeof(buffer),"%s pid:%d %d\n",s.c_str(),self,number++);

//用write寫入管道(管道也是文件),用strlen,不用+1,不用管\0,因為C語言規(guī)定\0結(jié)尾,和文件沒有關(guān)系,wfd寫入管道

write(wfd,buffer,strlen(buffer));

//cout<< buffer <

sleep(1);

};

}

父進程該怎么讀取呢

用到了read,fd是文件描述符,從特定的文件描述符里讀取,放在這個buf里,buf的長度是count

這里就需要考慮到\0,因為buffer中需要\0

//父進程

void Reader(int rfd)

{

char buffer[100];

while(true)

{

buffer[0] = 0;

//用sizeof是為了留個空間放\0

ssize_t n = read(rfd, buffer, sizeof(buffer));//sizeof!=strlen

if(n > 0)

{

//添加\0,因為要放在buffer數(shù)組中讀取

buffer[n]=0;

cout << "father get a message[" << getpid() <<"]"<< buffer <

}

}

}

運行結(jié)果

也會發(fā)現(xiàn):為什么子進程sleep,父進程不sleep,父進程還是會跟著子進程sleep,因為父子進程是要協(xié)同的

管道本質(zhì)

通信是為了更好的發(fā)送變化的數(shù)據(jù),管道本質(zhì)上是文件

所以必須要用到系統(tǒng)調(diào)用接口來訪問管道,其是由系統(tǒng)管理,read和write

,操作系統(tǒng)相當于中介?

結(jié)論:管道的特征:

1:具有血緣關(guān)系的進程進行進程間通信

2:管道只能單向通信

3:父子進程是會進程協(xié)同的,同步與互斥的--保護管道文件的數(shù)據(jù)安全

4:管道是面向字節(jié)流的

5:管道是基于文件的,而文件的生命周期是隨進程的

再測試,把子進程sleep去掉,就是讓子進程寫快一點,父進程sleep幾秒,就是讓父進程讀慢一點,看有什么現(xiàn)象

?管道的四種情況

測試管道大小

把c一直往管道里寫,把父進程中休眠50秒

結(jié)果差不多64kb

寫端退了,測試結(jié)果

結(jié)果是:

讀端正常讀,寫端關(guān)閉,讀端就會讀到0,表明讀到了文件(pipe)結(jié)尾,不會被阻塞

read讀取成功會返回讀到的字符個數(shù),讀到結(jié)尾返回0

讀到結(jié)尾父進程也就可以停止讀取了,break后去把僵尸的子進程回收

break到這里

最后子進程會被waitpid回收

測試子進程一直寫,父進程讀一會就退出

定義一個cnt控制退出的時間

這里也要修改一下,加個sleep(5),觀察,close提前關(guān)閉

結(jié)果:通過13號信號殺死?

管道到的應(yīng)用場景

都會變成一個進程

寫一個進程池(pipe_use)

首先創(chuàng)建好文件

創(chuàng)建5個進程

channel通道的意思

cmdfd文件描述符

slaverid代表哪個子進程

把它放進vector容器里

思路步驟

管道創(chuàng)建

void(n),假裝使用一下,要不然編譯不過

創(chuàng)建父子進程

父進程寫,子進程讀

子進程要讀取,就要關(guān)閉自己的寫端,父進程同理

子進程中的任務(wù)

子進程pid有了管道也有了,就差在父進程添加字段了

先更改一下,在class里構(gòu)造一下

添加字段

測試一下:結(jié)果:文件描述符0,1,2是默認打開,3是從管道里讀,4是寫入管道

把初始化改造成函數(shù)

debug測試函數(shù),純輸入函數(shù)

第二步開始控制進程了(想讓子進程做什么)

這里打印的rfd都是3,正常嗎,文件描述符是可以被子進程繼承的

父進程對應(yīng)的寫端拿到的是4-8,子進程拿到的讀端fd是3

改變一下,直接從鍵盤(0號描述符)里讀,不從管道(3)里讀了,就沒有管道的概念了,slaver就不用傳參了,父進程通過管道寫,子進程通過標準輸入讀

用到了dup2,將從pipefd[0]中讀變成從0開始讀

想讓父進程固定的向管道里寫入指定大小字節(jié)的內(nèi)容,必須讀取四個字節(jié),四個字節(jié)四個字節(jié)的寫和讀,這里的管道64kb

必須讀取四個字節(jié)

如果父進程不給子進程發(fā)送數(shù)據(jù)呢?阻塞等待!

開始控制子進程

生成一個隨機數(shù)種子

可以隨機選擇任務(wù)和選擇進程

cmd是任務(wù)碼,測試一下,父進程控制子進程,父進程發(fā)送給子進程(通過cmdcode連續(xù))

在Task.hpp里

要用到函數(shù)指針

main中的任務(wù)了就屬于

再把任務(wù)裝載進來

輸出型參數(shù)用*

現(xiàn)在開始選擇任務(wù)和進程

再把main中的任務(wù)弄成全局的

進行判斷一下

測試 ,comcode和任創(chuàng)建的任務(wù)一致

這里的write是父進程進行寫入,向子進程發(fā)送,子進程不得閑,先寫到管道里,等得閑了再讀

也可以輪詢選擇,定義一個計數(shù)器,++弄,再%等

整理一下控制代碼,這里是輸入型參數(shù),只需要讀

這樣就可以輪詢方式選擇進程了,不用隨機了

結(jié)果

清理收尾

思路:把所有文件的描述符都關(guān)掉

等待方式設(shè)置為0?

read返回0,就是失敗了,然后slaver就會調(diào)完

結(jié)束完就會exit直接退出

打印下更好顯示

關(guān)閉文件描述符后sleep(10)秒,

然后這10個子進程一瞬間都應(yīng)該break,然后最后到exit直接就退了,10秒結(jié)束后,父進程再回收他???????

測試時不弄死循環(huán),用cnt,5秒后自動結(jié)束控制,正常退出流程

測試結(jié)果

手動控制一下

定義一個select,輸入0就是退出了,判斷完后,就走到了選擇任務(wù)

然后直接把cmdcode改為選擇的select,-1是因為是從下標0開始的,輸入1就是0下標的

測試

bug的地方:

這樣會有一些bug(一個子進程不是只有一個寫端(每一次子進程的創(chuàng)建都是有繼承))

?這樣會有一些bug(一個子進程不是只有一個寫端(每一次子進程的創(chuàng)建都是有繼承))

按理說這樣是對的,可是這樣就錯了

因為下面兩個紅線還沒有關(guān)掉,它們進程了最開始的w

這樣倒著回收是可以的

正確改法

修改一下

最后一個push_back的就都是父進程的寫入fd,

然后加一句這個紅線的,每創(chuàng)建子進程后都先把上一次父進程的讀端fd關(guān)掉就可以了,這里很妙,因為vector一開始是空的

方便看

這里這樣就可以了????????

管道已經(jīng)完成

以上是匿名管道?

總文件總代碼

makefile中代碼

ProcessPool:ProcessPool.cc

g++ -o $@ $^ -std=c++11

.PHNOY:clean

clean:

rm -f ProcessPool

Task.hpp中代碼

#pragma once

#include

#include

using namespace std;

typedef void (*task_t)();

void task1()

{

cout<< "lol 刷新日志" <

}

void task2()

{

cout<< "lol 更新野區(qū)" <

}

void task3()

{

cout<< "lol 檢測軟件更新" <

}

void task4()

{

cout<< "lol 釋放技能" <

}

ProcessPool.cc中代碼

注意:

這里為啥是取地址一個comcode,不是一個0嗎,要發(fā)送的數(shù)據(jù)就是這個,所以要把地址傳給函數(shù),可以是個數(shù)組

換成數(shù)組的話,read這也接收數(shù)據(jù)的時候,就得用數(shù)組去接受,要是寫入超過int大小的話,就可能會出錯,這個就是通信的雙方要遵守的約定,這個判斷一下,就是派發(fā)的這個任務(wù)是不是合法的,假設(shè)你的tasks任務(wù)中,只有4個任務(wù),所以任務(wù)編號就是0 ~ 3,如果你接受到的任務(wù)編號是10或者-20,那么這些就是非法的,你執(zhí)行的話,程序就會崩潰,所以要做一個簡單的判斷。

write以后,cmdcode的值也會跟著傳到read對吧,write就是為了把cmdcode的值傳遞給給另外一個進程,以前見到的都是用的char buffer[];,這樣&cmdcode能更方便的傳值過去是不,看要傳的是什么數(shù)據(jù),只是傳遞一個int數(shù)據(jù)的話,就這樣傳遞,如果是文本數(shù)據(jù),或者是其他的話,可能就需要數(shù)組了,具體問題,具體討論

#include "Task.hpp"

#include

#include

#include

#include

#include

#include

#include

using namespace std;

//打算創(chuàng)建5個進程

const int processnum = 5;

//全局任務(wù)

vector tasks;

//先描述

class channel//管道

{

public:

channel(int cmdfd,pid_t slaverid,string& processname)

:_cmdfd(cmdfd)

,_slaverid(slaverid)

,_processname(processname)

{}

public:

int _cmdfd;//文件描述符

pid_t _slaverid;//代表哪個子進程

string _processname;//子進程的名字,方便打印日志

};

//子進程中讀的任務(wù)

// void slaver(int rfd)

// {

// while(true)

// {

// cout<< getpid() <<" - "<< "read fd is->"<

// sleep(1000);

// }

// }

//改變一下從fd為0的地方開始讀

void slaver()

{

//read(0);

while(true)

{

int cmdcode = 0;

int n = read(0, &cmdcode, sizeof(int));

if(n == sizeof(int))

{

//執(zhí)行cmdcode對應(yīng)的任務(wù)列表

cout<< "slaver say@ get a command:" << getpid() << ":cmdcode:" << cmdcode <

//判斷一下并執(zhí)行

if(cmdcode >= 0 && cmdcode < tasks.size()) tasks[cmdcode]();

}

if(n == 0) break;

}

}

//初始化

void Init(vector& channels)

{

for(int i =0;i < processnum;i++)

{

int pipefd[2];

int n = pipe(pipefd);//創(chuàng)建管道

//返回值小于0就創(chuàng)建失敗了

assert(!n);

(void)n;

pid_t id = fork();

if(id == 0)

{

//子進程:讀

close(pipefd[1]);

//改變一下從fd為0的地方讀

dup2(pipefd[0],0);

close(pipefd[0]);

//任務(wù)

slaver();

cout<< "process: " << getpid() << "quit" <

//slaver(pipefd[0]);

exit(0);

}

//父進程:寫

close(pipefd[0]);

//channel添加字段

string name = "processs-" + to_string(i);

//插入的是自定義類型,要構(gòu)造一下,第一個傳的是文件描述符,要寫入的fd

channels.push_back(channel(pipefd[1], id, name));

}

}

//測試函數(shù),純輸入函數(shù)

//輸入:const &

//輸出:*

//輸入輸出:&

void debug(const vector& channels)

{

for(auto&e : channels)

{

cout<< e._cmdfd <<" "<

}

}

void Loadtask(vector *tasks)

{

tasks->push_back(task1);

tasks->push_back(task2);

tasks->push_back(task3);

tasks->push_back(task4);

}

void memu()

{

cout<< "########################" <

cout<< "1:lol 刷新日志 2:lol 更新野區(qū)" <

cout<< "1:lol 檢測軟件更新 4:lol 釋放技能" <

cout<< " 0:退出 " <

cout<< "########################" <

}

//2:開始控制子進程

void ctrlSlaver(vector &channels)

{

int which = 0;

int cnt = 5;

while(true)

{

int select = 0;

memu();

cout<< "Please Enter@:";

cin>> select;

if(select == 0) break;

//1:選擇任務(wù)

//int cmdcode = rand()%tasks.size();

int cmdcode = select - 1;

//2:隨機選擇進程

//int processpos = rand()%channels.size();

//2:輪詢選擇進程

cout<< "father say:"<< "cmdcode:" << cmdcode << " already sendto " <

<

//3:發(fā)送任務(wù)

write(channels[which]._cmdfd, &cmdcode, sizeof(cmdcode));

which++;

which%=channels.size();//保證不大于其長度

cnt--;

if(cnt == 0) break;

sleep(1);

}

}

void QuitProcess(const vector &channels)

{

for(const auto& e : channels) close(e._cmdfd);

sleep(10);

for(const auto& e : channels) waitpid(e._slaverid, nullptr, 0);//進程的pid=_slaverid,關(guān)上了以后記得回收

}

int main()

{

Loadtask(&tasks);

//srand(time(nullptr)^getpid()^1023);//種一個隨機數(shù)種子

//在組織

vector channels;

//1:初始化

Init(channels);

debug(channels);

//2:開始控制子進程

ctrlSlaver(channels);

//3:清理收尾

QuitProcess(channels);

return 0;

}

柚子快報邀請碼778899分享:算法 匿名管道 Linux

http://yzkb.51969.com/

文章來源

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19544806.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機訪問

文章目錄