做英文网站公司,自己建网站模板,网络建设推广,浙江大学微纳加工平台人与人之间是如何通信的#xff1f;举个简单的例子#xff0c;假如我是月老#xff0c;我要为素不相识的但又渴望爱情的男女两方牵红线。我需要收集男方的信息告诉女方#xff0c;收集女方的信息告诉男方#xff0c;然后由男女双方来决定是否继续。对于他们而言#xff0…人与人之间是如何通信的举个简单的例子假如我是月老我要为素不相识的但又渴望爱情的男女两方牵红线。我需要收集男方的信息告诉女方收集女方的信息告诉男方然后由男女双方来决定是否继续。对于他们而言通信由一方发起另一方判断是否进行接收我是他们之间进行通信的媒介是否继续进行通信的决定权在男女双方手中。男女两方通过月老进行传话、从月老获取信息的方式实现了男女双方间的间接通信。
在上述场景中月老独立于男女方之间但又能为男女方之间建立联系。而进程拥有独立的地址空间进程之间的交流也需要依赖于类似于“月老”的“公共资源”。不同进程间通过对公共资源的读写操作就可以间接实现进程间的通信。
一、进程间通信方式概述 进程间通信就是在不同的进程间传播或交换信息但由于进程的用户空间是相互独立的他们之间是不能直接进行互相访问的。在这种情况下我们想让不同进程间进行通信就必须为这些进程之间提供一个“公共区域”而这块公共区域不能单独属于某一个进程的地址空间必须独立于各个进程间且允许被进行通信的进程进行访问。显然广义上系统内核空间、磁盘文件、数据库等都可以作为进程间交流的媒介。 但通常我们将使用内核空间进行进程间交流的方式称为“进程间通信”。 在Linux系统中进程间的通信方式有管道、消息队列、信号、信号量、共享内存、套接字等方式。而管道通信方式又分为“匿名管道”和“命名管道”两种方式。
常见的进程间通信机制
管道Pipes允许数据在两个进程之间流动。包括匿名管道和命名管道FIFO。消息队列Message Queues允许进程以消息的形式交换信息。共享内存Shared Memory多个进程可以访问同一块内存区域以实现高效的数据交换。信号量Semaphores用于实现进程间的同步和互斥控制。信号Signals用于通知进程某个事件的发生。套接字Sockets用于不同主机或同一主机上不同进程之间的通信尤其适用于网络通信。
二、进程间通信的目的
数据传输在不同进程之间传递数据或状态信息。协调与同步协调进程间的操作避免冲突确保一致性。资源共享允许多个进程共享系统资源如文件或内存。任务分配将任务分配给多个进程提高处理效率和负载均衡。消息传递传递控制信息、指令或状态更新等。
三、管道的特点 1、匿名管道只能用于父子进程、兄弟进程等具有“亲缘关系”的进程之间。
2、管道是半双工的即数据只能往一个方向流动如果需要进行进程间的双方通信则需要创建两个管道。
3、管道单独构成一种独立的文件系统。管道对于两端的进程而言就是一个文件但他不是普通的文件并不属于某种文件系统而是自立门户单独构成一种文件系统并且只存在于内存中。
4、一个进程向管道中写入的内容被管道的另一端的进程读出。写入的内容每次被添加在管道缓冲区的末尾并且每次都是从缓冲区的头部读出数据。
5、管道的写入操作是非原子的这意味着如果尝试一次性写入大量数据当数据量超过管道的最大容量时一般是4096字节可以自行测试操作系统可能不会将所有数据一次性放入管道。相反它可能会将数据分成几个部分并且接收端可能需要多次读取操作才能接收完整的消息。类似的当管道中还有未被读取的数据时当管道中的剩余空间不足以一次性将数据全部写入时写端会先将剩余空间写满然后写端进程会阻塞在写端。当读端进程对管道数据进行读入时管道一出现剩余空间写端进程就会继续写入。
管道中的数据就像流动的水而管道就像一个水管。我们将写端视为自来水厂读端视为水龙头。当水龙头打开时水流会源源不断地从水厂经过管道流到水龙头处工厂提供多少水就用多少水。而当水龙头关闭时水厂的水就会阻塞在管道前等待下一次供水。而当水厂倒闭后再次打开水龙头时流出的水量只是当初残留在管道中的部分也可能管道中已经没有残留的水了当使用完管道中的水后水龙头也没有存在的必要了因为与水龙头连接的供应端已经无法供应水流这时我们只能关闭水龙头了。
在上述例子中写端就是自来水厂管道就是水管读端就是水龙头。当管道中有数据时我们就可以对其进行读取操作。数据在管道中也可以看作是“流动的”当读端读取数据后所读取到的数据在管道中也就“不复存在了”此时管道中会出现“剩余空间”只要还有剩余空间写端就可以往管道中进行写入。
假设你有一个管道缓冲区大小是 4KB如果你试图写入 10KB 的数据操作系统会将数据分成多个块进行处理
第一次写入 4KB 数据管道的缓冲区会填满。如果缓冲区满了写操作会阻塞直到有足够的空间。等到读取端消费了一部分数据管道中会有新的空间写操作才会继续。
这也是为什么Linux不保证管道写入数据的原子性——数据是“流动的”。
写入的原子性只有写完数据和不写入数据两种结果不存在只写一部份的情况。由此可见管道的写入不符合原子性。
四、 匿名管道的创建
在Linux系统中pipe函数用于创建一个匿名管道并且当这个函数成功执行后管道的读端和写端文件描述符是默认被打开的。这些文件描述符可以用于在进程之间传递数据实现进程间的通信。匿名管道只能作用于有亲缘关系的进程之间的通信比如父进程和子进程。 函数原型 int pipe(int pipefd[2]); 参数 pipefd[2] 是一个整型数组输出型参数用于返回管道的读端和写端的文件描述符pipefd[0] 是管道的读端文件描述符pipefd[1] 是管道的写端文件描述符。 返回值 函数执行成功返回0若失败则返回 -1并将错误原因存于errno中。 当父进程调用pipe函数创建匿名管道文件时操作系统会在调用该函数的进程空间中为其分配两个新的文件描述符一个用于管道的读端另一个用于写端。如果之前没有打开其他文件或管道文件描述符 0标准输入、1标准输出和 2标准错误通常会被保留而管道的文件描述符会被分配为 3、4 或更高的数字。 五、父子进程使用匿名管道进行通信的简单示例
当使用fork()创建子进程后子进程会继承父进程的资源这其中就包括父进程中为已经打开的文件分配的文件描述符。所以子进程的文件描述符表中也会存在父进程所创建的匿名管道文件的读端和写端文件描述符。因此匿名管道只能作用于有亲缘关系的进程之间的通信的实质是具有亲缘关系 的进程中拥有相同的文件描述符表。
当我们确定好数据的流向后应关闭不再需要的文件描述符原因如下1、长时间运行的程序如果不断打开新的文件描述符而不关闭旧的最终可能会耗尽系统资源。2、管道是单向的数据从写端流向读端。如果一个进程同时拥有读端和写端的文件描述符那么它就可以既读取又写入数据这可能会导致不可预测的行为和数据混乱。通过在一个进程中关闭读端在另一个进程中关闭写端可以明确数据流的方向并确保每个进程只负责管道的一端。
例如当确定父进程进行写入、子进程进行读取时我们需要父进程的读端和子进程的写端确保数据是从父进程单向流入子进程的。
自此我们通过write()函数对父进程中的写端进行写入、使用read()函数对子进程中的读端进行读取自此就实现了父子进程间的通信。
下面是一个父进程通过管道向子进程传递“hello world!\n字符串并打印至屏幕上的例子
#include unistd.h
#include errno.h
#include iostream
#include cstring
#include sys/types.h
#include sys/wait.h#define BUFFER_SIZE 1024 //定义缓冲区大小int main()
{int pipefd[2];if (pipe(pipefd) -1){std::cerr Pipe create failed : strerror(errno) std::endl;exit(-1);}pid_t id fork();if (id 0){close(pipefd[1]);//子进程先关闭写端char buffer[BUFFER_SIZE];int number 0;if ((number read(pipefd[0], buffer, sizeof(buffer) - 1)) -1)//读入size-1个字节的数据为\0字符留一个空间{std::cerr Read failed : strerror(errno) std::endl;exit(-1);}buffer[number] \0;//字符数组末尾设置为\0字符std::cout 子进程输出 buffer std::endl;close(pipefd[0]);//子进程退出前关闭读端}else if (id 0){close(pipefd[0]);//父进程关闭读端char str[] hello world!;if (write(pipefd[1], str, sizeof(str)) -1)//向管道中写入字符串{std::cerr Write failed : strerror(errno) std::endl;exit(-1);}close(pipefd[1]);//父进程关闭写端int status 0;if (waitpid(id, status, 0) -1)//等待子进程退出{std::cerr Wait failed : strerror(errno) std::endl;}else{if (WIFEXITED(status))//如果是正常退出{std::cout 退出状态 WEXITSTATUS(status) std::endl;} else if (WIFSIGNALED(status)) //如果是收到信号{std::cout 终止信号 WTERMSIG(status) std::endl;}}}else{std::cerr fork failed! strerror(errno) std::endl;exit(-1);}return 0;
}
六、 匿名管道的规则与特征
1、如果管道的写端没有关闭但进程A未往管道中写入数据此时管道中没有数据。在进程B的读端未关闭的情况下读端进程将阻塞在read()处直到管道中写入数据read()函数成功读取数据之后继续执行后续代码。
2、如果写端关闭了如果管道中仍有未被读取的数据则读端继续读直到读完管道中的数据时read()函数返回0表示读到了文件的末尾。如果写端关闭且管道中没有数据则read()函数直接返回0意味着读到了文件的末尾。此时我们应在代码中进行判断当read()函数返回值为0时主动关闭读端退出程序。
3、如果管道的读端没有关闭但读端不读入数据写端会一直向管道中写入数据直到管道被写满。此时写进程会阻塞在写端直到读端进程对管道中的数据进行读入。
4、如果读端关闭了写端还在写那么操作系统将会给写端进程发送SIGPIPE信号默认终止写端进程。
对于如上规则对“模块五”中的代码稍作修改即可验证此处不再进行代码验证。由于规则4需要对管道流向进行改变所以此处仅验证规则4
由于我们需要判断当读端关闭时写端进程是否会收到SIGPIPE信号所以我们让父进程作为读端进程子进程作为写端进程使用waitpid()函数获取子进程的退出信号。
#include unistd.h
#include errno.h
#include iostream
#include cstring
#include sys/types.h
#include sys/wait.h#define BUFFER_SIZE 1024 // 定义缓冲区大小int main()
{int pipefd[2];if (pipe(pipefd) -1){std::cerr Pipe create failed : strerror(errno) std::endl;exit(-1);}pid_t id fork();if (id 0){close(pipefd[0]); // 父进程关闭读端char str[] hello world!;while (true){if (write(pipefd[1], str, sizeof(str)) -1) // 向管道中写入字符串{std::cerr Write failed : strerror(errno) std::endl;exit(-1);}}close(pipefd[1]); // 父进程关闭写端}else if (id 0){close(pipefd[1]); // 子进程先关闭写端char buffer[BUFFER_SIZE];int r_number 0;while (true){if ((r_number read(pipefd[0], buffer, sizeof(buffer) - 1)) -1) // 读入size-1个字节的数据为\0字符留一个空间{std::cerr Read failed : strerror(errno) std::endl;break;}if (r_number 0){std::cout 写端关闭读到了文件末尾读端进程退出 std::endl;break;}else{buffer[r_number] \0; // 字符数组末尾设置为\0字符std::cout 子进程输出 buffer std::endl;}close(pipefd[0]); // 子进程退出前关闭读端}int status 0;if (waitpid(id, status, 0) -1) // 等待子进程退出{std::cerr Wait failed : strerror(errno) std::endl;}else{if (WIFEXITED(status)) // 如果是正常退出{std::cout 退出状态 WEXITSTATUS(status) std::endl;}else if (WIFSIGNALED(status)) // 如果是收到信号{std::cout 终止信号 WTERMSIG(status) std::endl;}}}else{std::cerr fork failed! strerror(errno) std::endl;exit(-1);}return 0;
} 可以观察到当读端关闭后read()函数读取失败返回-1。此时写进程收到13号信号由于写进程中未对信号进行捕捉处理所以写端进程默认进行退出。
七、匿名管道的应用实例
实例一用于shell
管道可用于输入输出重定向他将一个命令的输出直接定向到另一个命令的输入。例如当在命令行中输入“who | wc -l”后shell程序将创建who 和 wc两个进程以及这两个进程间的管道 实例二 父进程向子进程派发任务
场景程序中存在一系列任务父进程通过对子进程发送任务编号/任务名称等方式让子进程去实现指定的任务。
#include unistd.h
#include errno.h
#include iostream
#include cstring
#include sys/types.h
#include sys/wait.h
#include functional
#include vector#define BUFFER_SIZE 1024 // 定义缓冲区大小
#define TASK_NUM 2 // 定义任务数量using func_t std::functionint(int, int);
std::vectorfunc_t func(TASK_NUM);void SetTask()
{func[0] [](int a, int b){return a b;};func[1] [](int a, int b){return a - b;};
}int HandleTask(int index)
{if(index 0 || index 1){std::cout 任务列表中暂无此任务 std::endl;return 0;}std::cout 请输入两个操作数;int a 0, b 0;std::cin a b;int ret func[index](a, b);std::cout 结果为 ret std::endl;return 1;
}int main(int argc, char *argv[])
{SetTask();//设置任务int pipefd[2];if (pipe(pipefd) -1){std::cerr Pipe create failed : strerror(errno) std::endl;exit(-1);}pid_t id fork();if (id 0){close(pipefd[1]); // 子进程先关闭写端while(true){char buffer[2];int number 0;if ((number read(pipefd[0], buffer, sizeof(buffer) - 1)) -1) // 读入size-1个字节的数据为\0字符留一个空间{std::cerr Read failed : strerror(errno) std::endl;break;}else if (number 0){std::cout 子进程退出 std::endl;break;}else {buffer[number] \0; // 字符数组末尾设置为\0字符int ans atoi(buffer);if(!HandleTask(ans)){std::cout 子进程调用任务失败 std::endl;break;}} }close(pipefd[0]); // 子进程退出前关闭读端}else if (id 0){close(pipefd[0]); // 父进程关闭读端for(int i 1; i argc; i){if (write(pipefd[1], argv[i], strlen(argv[i])) -1) // 向管道中写入字符串{std::cerr Write failed : strerror(errno) std::endl;exit(-1);}}close(pipefd[1]); // 父进程关闭写端int status 0;if (waitpid(id, status, 0) -1) // 等待子进程退出{std::cerr Wait failed : strerror(errno) std::endl;}else{if (WIFEXITED(status)) // 如果是正常退出{std::cout 退出状态 WEXITSTATUS(status) std::endl;}else if (WIFSIGNALED(status)) // 如果是收到信号{std::cout 终止信号 WTERMSIG(status) std::endl;}}}else{std::cerr fork failed! strerror(errno) std::endl;exit(-1);}return 0;
}【下一节基于匿名管道通信实现的进程池】 文章转载自: http://www.morning.rynrn.cn.gov.cn.rynrn.cn http://www.morning.cokcb.cn.gov.cn.cokcb.cn http://www.morning.bangaw.cn.gov.cn.bangaw.cn http://www.morning.htjwz.cn.gov.cn.htjwz.cn http://www.morning.wjrtg.cn.gov.cn.wjrtg.cn http://www.morning.c7500.cn.gov.cn.c7500.cn http://www.morning.gnhsg.cn.gov.cn.gnhsg.cn http://www.morning.dpfr.cn.gov.cn.dpfr.cn http://www.morning.zfkxj.cn.gov.cn.zfkxj.cn http://www.morning.zpfr.cn.gov.cn.zpfr.cn http://www.morning.xjkfb.cn.gov.cn.xjkfb.cn http://www.morning.bnxnq.cn.gov.cn.bnxnq.cn http://www.morning.clpkp.cn.gov.cn.clpkp.cn http://www.morning.snbry.cn.gov.cn.snbry.cn http://www.morning.tktyh.cn.gov.cn.tktyh.cn http://www.morning.mszls.cn.gov.cn.mszls.cn http://www.morning.mmosan.com.gov.cn.mmosan.com http://www.morning.bzgpj.cn.gov.cn.bzgpj.cn http://www.morning.c7501.cn.gov.cn.c7501.cn http://www.morning.bqmhm.cn.gov.cn.bqmhm.cn http://www.morning.tgwfn.cn.gov.cn.tgwfn.cn http://www.morning.gstg.cn.gov.cn.gstg.cn http://www.morning.yslfn.cn.gov.cn.yslfn.cn http://www.morning.pkpqh.cn.gov.cn.pkpqh.cn http://www.morning.hyryq.cn.gov.cn.hyryq.cn http://www.morning.hgbzc.cn.gov.cn.hgbzc.cn http://www.morning.rfkyb.cn.gov.cn.rfkyb.cn http://www.morning.dlmqn.cn.gov.cn.dlmqn.cn http://www.morning.ghccq.cn.gov.cn.ghccq.cn http://www.morning.rmdsd.cn.gov.cn.rmdsd.cn http://www.morning.ahscrl.com.gov.cn.ahscrl.com http://www.morning.thrcj.cn.gov.cn.thrcj.cn http://www.morning.cpwmj.cn.gov.cn.cpwmj.cn http://www.morning.gnwpg.cn.gov.cn.gnwpg.cn http://www.morning.pxbky.cn.gov.cn.pxbky.cn http://www.morning.ljcf.cn.gov.cn.ljcf.cn http://www.morning.rnmmh.cn.gov.cn.rnmmh.cn http://www.morning.ptmgq.cn.gov.cn.ptmgq.cn http://www.morning.dtzxf.cn.gov.cn.dtzxf.cn http://www.morning.qrwjb.cn.gov.cn.qrwjb.cn http://www.morning.hpprx.cn.gov.cn.hpprx.cn http://www.morning.mnwb.cn.gov.cn.mnwb.cn http://www.morning.rkfxc.cn.gov.cn.rkfxc.cn http://www.morning.ffydh.cn.gov.cn.ffydh.cn http://www.morning.pngfx.cn.gov.cn.pngfx.cn http://www.morning.tsdqr.cn.gov.cn.tsdqr.cn http://www.morning.yckwt.cn.gov.cn.yckwt.cn http://www.morning.pmwhj.cn.gov.cn.pmwhj.cn http://www.morning.swdnr.cn.gov.cn.swdnr.cn http://www.morning.lsmgl.cn.gov.cn.lsmgl.cn http://www.morning.xkpjl.cn.gov.cn.xkpjl.cn http://www.morning.kztts.cn.gov.cn.kztts.cn http://www.morning.dfqmy.cn.gov.cn.dfqmy.cn http://www.morning.lmmyl.cn.gov.cn.lmmyl.cn http://www.morning.kqgsn.cn.gov.cn.kqgsn.cn http://www.morning.gglhj.cn.gov.cn.gglhj.cn http://www.morning.dwztj.cn.gov.cn.dwztj.cn http://www.morning.ndpwg.cn.gov.cn.ndpwg.cn http://www.morning.kcdts.cn.gov.cn.kcdts.cn http://www.morning.qrwjb.cn.gov.cn.qrwjb.cn http://www.morning.wmcng.cn.gov.cn.wmcng.cn http://www.morning.bdsyu.cn.gov.cn.bdsyu.cn http://www.morning.dmlgq.cn.gov.cn.dmlgq.cn http://www.morning.ndmh.cn.gov.cn.ndmh.cn http://www.morning.qblcm.cn.gov.cn.qblcm.cn http://www.morning.hpdpp.cn.gov.cn.hpdpp.cn http://www.morning.txfxy.cn.gov.cn.txfxy.cn http://www.morning.lpmlx.cn.gov.cn.lpmlx.cn http://www.morning.nqxdg.cn.gov.cn.nqxdg.cn http://www.morning.cmhkt.cn.gov.cn.cmhkt.cn http://www.morning.srgbr.cn.gov.cn.srgbr.cn http://www.morning.cpfbg.cn.gov.cn.cpfbg.cn http://www.morning.kjnfs.cn.gov.cn.kjnfs.cn http://www.morning.knjj.cn.gov.cn.knjj.cn http://www.morning.fpzpb.cn.gov.cn.fpzpb.cn http://www.morning.drjll.cn.gov.cn.drjll.cn http://www.morning.kqhlm.cn.gov.cn.kqhlm.cn http://www.morning.wnqfz.cn.gov.cn.wnqfz.cn http://www.morning.zqxhn.cn.gov.cn.zqxhn.cn http://www.morning.mzhh.cn.gov.cn.mzhh.cn