当前位置: 首页 > news >正文

博客论坛网站开发seo排名赚app多久了

博客论坛网站开发,seo排名赚app多久了,网站建设意见征求汇报,国际贸易网站哪家好1.进程间通信介绍 进程是计算机系统分配资源的最小单位#xff08;严格说来是线程#xff09;。每个进程都有自己的一部分独立的系统资源#xff0c;彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作#xff0c;才有了进程间通信。 进程间通信#xff0c;顾名…1.进程间通信介绍 进程是计算机系统分配资源的最小单位严格说来是线程。每个进程都有自己的一部分独立的系统资源彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作才有了进程间通信。 进程间通信顾名思义就是进程与进程之间互通信交流OS保证了各进程之间相互独立但这不意味着进程与进程之间就必须完全隔离开在不少的情况下进程之间需要相互配合共同完成某项任务这就要求各进程之间能够互相交流。 1.1、进程间通信的概念 每个进程各自有不同的用户地址空间任何一个进程的全局变量在另一个进程中都看不到所以进程之间要交换数据必须通过内核在内核中开辟一块缓冲区进程1把数据从用户空间拷到内核缓冲区进程2再从内核缓冲区把数据读走内核提供的这种机制称为进程间通信IPCInterProcess Communication 1.2.进程间通信的目的 进程间通信的目的和原因有如下几个点 数据传输一个进程需要将它的数据发送给另一个进程资源共享多个进程之间共享同样的资源通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有陷入和异常并能够及时知道它的状态改变 总得来说实现进程间通信就是为了进程之间能够协同完成某项任务 1.3..进程间通信的本质 进程间通信的本质是让 不同的进程看到同一份资源(内存 文件内核缓冲等) 资源由谁OS的哪些模块提供 就有了不同的进程间通信方式 这里的模块可以是: (文件–管道) , (OS内核IPC提供- SystemV IPC) , (网络–套接字)                                  a.进程运行的时候是具有独立性的!数据层面) , 因此进程之间要实现通信是非常困难的。b.进程间通信一般一定要借助第三方(OS)资源。c.通信的本质就是”数据的拷贝“ 1.4.进程间通信分类 管道 匿名管道命名管道 System V IPC System V 消息队列System V 共享内存System V 信号量 POSIX IPC 消息队列共享内存信号量互斥量条件变量读写锁 进程间通信起初有很多不同的的相关协议随着不断的实践发展目前主要有两个主流的通信规则一个是System V另一个是POSIX POSIX让通信过程可以跨主机System V聚焦在本地通信         由于System V由于制定的比较早不支持跨主机间的通信在今天属于比较陈旧的标准了因此我们会将更多精力放在POSIX上不过POSIX通信并不是这篇文章的内容因此不会提及而System V我们关注比较重要的共享内存的概念通信规则并非只局限于POSIX和System V我们先介绍比较简单易接受的管道通信 2.管道通信 1.什么是管道 管道是Unix中最古老的进程间通信的形式。我们把从一个进程连接到另一个进程的一个数据流称为一个管道管道是一种最基本的进程间通信机制。 把一个进程连接到另一个进程的一个数据流称为一个“管道”通常是用作把一个进程的输出通过管道连接到另一个进程的输入。 管道的实质是一个内核缓冲区进程以先进先出的方式从缓冲区存取数据管道一端的进程顺序的将数据写入缓冲区另一端的进程则顺序的读出数据。 该缓冲区可以看做是一个循环队列读和写的位置都是自动增长的不能随意改变一个数据只能被读一次读出来以后在缓冲区就不复存在了。  2.管道, 其实是 一个打开的文件 . 但是这个文件很特殊, 向这个文件中写入数据实际上并不会真正写入磁盘中. 在介绍Linux系统的文件描述符时, 简单介绍了Linux系统中 描述已打开文件的结构体files_struct, 其中存储着 指向打开文件的数组fd_array, 此数组的类型是 struct files*. 而这个 files结构体中, 直接或间接描述了文件的所有属性, 以及 此文件的缓冲区相关信息 缓冲区信息中, 包含着描述文件的inode结构体, 而inode结构体中其实描述着一个联合体 这个处于inode结构体中的联合体, 其实就是为了标识这个文件的类型, 其中pipe 就表示此文件的类型是管道文件. 通过文件的inode, 系统可以辨别出打开的文件是管道文件. 而**向管道文件中写入数据实际上并不会写入到磁盘上, 而是只写入到文件的缓冲区中** , 因为管道文件主要是用来进程间通信的, 如果先写入磁盘另一个进程再读取, 整个过程就太慢了 这种不实际存储数据的行为特点, 其实也符合生活中管道的特点, 管道不能用来存储资源, 只能用来传输资源 并且, 除了管道不实际存储资源以外, 管道还有一个特点管道是单向传输的 这是管道的特点, Linux的管道也是遵循这个特点的, 也就是说, 两个进程间使用管道通信时, 其中一个进程若以只写方式打开管道, 那么另一个进程就只能以只读方式打开文件. 3.管道通信主要是借助文件系统来实现的怎么理解呢 我们假设现在系统上的进程A和进程B要互相通信A不能直接去B里面读数据因为进程具有独立性那该怎么办呢这就需要找一块空间C空间C用来存放通信双方通信的数据现在进程A要给B发送数据那么A和B要向系统声明建立连接申请一块空间C然后A往空间C里发送数据B从空间C里读取数据这样A就实现了和B的通信这块空间C就像一根管道一样连接着A与B整个管道通信的基本原理就是如此当然这只解释了管道名称的由来并没有解释管道通信是借助文件系统来实现的 我们要理清楚如何在Linux系统中让两个进程读取到同一块内存空间如果看过IO篇的同学应该会想到那就是通过文件进程从磁盘中或除自身以外的其他可读写的内存区域中读取或写入数据主要是通过文件系统来解决的只要系统在内存中创建一个文件A进程打开这个文件B进程也打开这个文件那么A与B就通过这个文件连接起来进行通信了这就是管道通信是借助文件系统来实现的原因 我们举个例子         在shell中执行命令经常会将上一个命令的输出作为下一个命令的输入由多个命令配合完成一件事情。而这就是通过管道来实现的。|这个竖线就是管道符号 ls -l | grep string //grep是抓取指令ls命令其实也是一个进程会把当前目录中的文件都列出来但它不会直接输出而是把要输出到屏幕上的数据通过管道输出到grep这个进程中作为grep这个进程的输入然后这个进程对输入的信息进行筛选grep的作用把存在string的信息的字符串以行为单位打印在屏幕上。 3.匿名管道 经过上述的说明我们已经明白了管道通信就是用来实现进程与进程之间的通信但是进程与进程之间的通信也分为两种 一种是父子进程或兄弟进程之间的通信另一种则是没有亲属关系的进程间的通信 匿名管道的创建, 不会指定打开文件的文件名、文件路径等, 即不会有目标的打开文件 只是在内存中打开一个文件, 用于进程间的通信 而由于匿名管道是非明确目标的文件, 也就意味着两个完全不相关的进程是无法一起访问这个管道的, 因为完全不相关的进程无法找到这个管道文件. 这也就意味着, 匿名管道其实只能用于具有血缘关系的进程间通信. 父子进程之间是共享代码和数据的但这个数据共享只能用来读一旦一方试图使数据发生变化会触发写时拷贝父进程与子进程的数据就存放到了不同的地址这时父子双方该如何通知对方数据发生了变化呢         这就是匿名管道通信要研究的东西 进程间通信的本质就是让不同的进程看到同一份资源使用匿名管道实现父子进程间通信的原理就是让两个父子进程先看到同一份被打开的文件资源然后父子进程就可以对该文件进行读写操作进而实现父子进程间通信 子进程拷贝父进程的fd_array父子进程看到同一份文件 , 这里父子进程看到的同一份文件资源是由操作系统来维护的所以当父子进程对该文件进行写入操作时该文件缓冲区当中的数据并不会进行写时拷贝(文件并不存在磁盘只在内存中存在)。 管道虽然用的是文件的方案但操作系统一定不会把进程进行通信的数据刷新到磁盘当中因为这样做有IO参与会降低效率。也就是说这种文件是一批不会把数据写到磁盘当中的文件换句话说磁盘文件和内存文件不一定是一 一对应的有些文件只会在内存当中存在而不会在磁盘当中存在 3.1.创建匿名管道的原理 创建一个管道也就是系统在内存中创建一个文件进程A与进程B通过这个文件互相读取数据这就涉及到另一个问题是否进程A和进程B可以双向通信即都可向管道文件中读写数据若可以则进程A与B又该如何分辨自己该读取哪部分数据呢         可能你会说等A写完B赶紧读然后B再写A再读这样会有潜在的隐患因为A写的时候你要阻止B写入如果这个时候B有很重要的数据不能及时写入就造成数据丢失         因此我们规定管道通信都是单向通信创建一个管道时只能由一方负责写一方负责读这是在创建管道时就要决定好的如果要实现双方都可以读写那就创建两个管道创建两个管道无非是创建两个文件罢了开销并不大         管道的通信是单向的也就是A进程在管道通信时既可以做写方又可以做读方系统如何区分此时A是写还是读呢         解决办法就是让父进程以读和写两种形式分别打开管道文件也就是我们需要一个数组这个数组只有两个元素用来记录以读的形式打开管道文件的fd以及以写的形式打开管道文件的fd然后根据相关情况选择关闭其中一个这也是为什么在声明管道通信前要先声明 我们从文件描述符视角来看 这个过程 也就是说, 匿名管道的创建应该是 由父进程创建, 然后创建子进程继承父进程的管道, 然后再关闭管道的写入端或读取端 这样就创建了一个管道通信 1.为什么父子进程要分别以只读和只写方式打开两次文件, 然后再创建子进程呢 为什么不是父进程以一个方式打开, 子进程再以另一个方式打开呢 因为子进程会以继承父进程的方式打开同一个文件, 即子进程打开文件的方式与父进程是相同的 那这样的话, 父子进程通过想要通过管道实现进程通信, 子进程就需要先关闭已打开的文件, 再以某种方式打开同一个文件 这样比较麻烦, 如果在创建子进程之前, 父进程就已经以两种方式打开同一个文件, 那么再子进程创建之后, 只需要父进程关闭一个端口, 子进程关闭另一个端口就可以了 2.必须父进程关闭读取端, 子进程关闭写入端吗 并不是的, 父子进程关闭哪个端口, 其实是 根据需求 关闭的. 如果子进程要向父进程传输数据, 那么关闭读取端的就应该是子进程 3.进程是如何知道管道被打开了什么端口的或者说 进程是如何知道管道被打开了几次的 其实在file结构体中, 存在一个计数变量 f_count 不过, 这个变量实际上还是一个结构体, 用于计数 很好到这里原理结束 3.2.pipe函数 Linux操作系统提供了一个接口来进行匿名管道的创建与使用  #include unistd.hint pipe(int fd[2]); //功能:创建一个无名管道 fd文件描述符数组,其中fd[0]表示读端, fd[1]表示写端返回值:成功返回0失败返回错误代码 注意该函数的参数是输出型参数在传参fd时要先创建fd也就是事先声明 int fd[2]; 且, pipe(), 如果 创建管道成功, 则返回0, 否则返回-1, 并设置errno pipe系统调用的作用是, 打开一个管道文件. 其参数是一个 输出型参数 在pipe系统调用 执行成功之后, 参数数组内会存储两个元素  pipe[0], 存储以 只读方式 打开管道时获得的fdpipe[1], 存储以 只写方式 打开管道时获得的fd 之后就可以根据需求, 选择父子进程的端口关闭 3.3.创建匿名管道 我们将按照原理一步一步来讲解 int fd[2];//这个语句就是用来记录进程分别以读写端打开管道文件的fd int main() {int fd[2];int check pipe(fd);if (check ! 0) {printf(create pipe error\n);return 0;}} 父进程在创建子进程时子进程会拷贝一份父进程的进程地址空间同样的子进程也会拷贝父进程的文件描述符表 int main() {int fd[2];int check pipe(fd);if (check ! 0) {printf(create pipe error\n);return 0;}pid_t id fork();if (id 0) { /*执行父进程代码*/ };if (id 0) { /*执行子进程代码*/ };return 0;} 接下来我们明确父子进程谁是读端谁是写端就可以进行通信了这里我们让父进程写数据给子进程那么父进程就要关闭自己的读端子进程就要关闭自己的写端 fd[0]是读端fd[1]是写端 巧记按照读音的顺序读写01正好对应。还有1像一支笔所以是写端0像张开的嘴所以是读端 int main() {int fd[2];int check pipe(fd);if (check ! 0) {printf(create pipe error\n);return 0;}pid_t id fork();if (id 0) { close(fd[0]);/*关闭父进程的读端接着执行父进程代码*/ };if (id 0) { close(fd[1]);/*关闭子进程的写端接着执行子进程代码*/ };return 0;} 现在读写双方都确定了那写方如何给读方发数据读方又如何读取写方的数据呢 既然管道通信是借助文件系统实现的那么是不是......没错就是使用read和write函数接下来通过一个demo来示例这个通信过程 #includestdio.h #includestring.h #includeunistd.h #includestdlib.h #includesys/stat.h #includesys/types.h #includefcntl.h #includesys/wait.hint main() {int fd[2];int check pipe(fd);//声明创建管道if (check ! 0) { printf(create pipe error); return 0; }char test_buff[64] this is a communication test;pid_t id fork();if (id 0) {close(fd[0]);write(fd[1], test_buff, sizeof(test_buff));wait();}if (id 0) {close(fd[1]);memset(test_buff, 0, sizeof(test_buff));read(fd[0], test_buff, sizeof(test_buff));printf(测试结果%s\n, test_buff);}return 0; } 我们成功实现了父子进程之间的通信接下来我们修改部分代码然后刨析一下通信的过程 如下是修改后的代码以及运行结果 #includeiostream #include string.h #include unistd.h #include stdlib.h #include sys/stat.h #include sys/types.h #include fcntl.h #includesys/wait.husing namespace std;int main() {int fd[2];int check pipe(fd);if (check ! 0) { std::cout create pipe error endl; return 0; }char test_buff[64] this is a communication test;pid_t id fork();if (id 0){close(fd[0]);write(fd[1], test_buff, sizeof(test_buff));std::cout 我是父进程我的pid是getpid() endl;}if (id 0){close(fd[1]);while (true){sleep(1);memset(test_buff, 0, sizeof(test_buff));read(fd[0], test_buff, sizeof(test_buff)-1);std::cout 我是子进程我的pid是getpid() endl;std::cout test_buff endl;}}wait(nullptr);return 0; } 1.观察运行结果可以发现子进程循环两次后就卡在了那里不动了这是什么原因呢 这是因为read函数是一个阻塞式函数在上述程序中父进程往管道中写入一次数据后就进入了wait阻塞等待回收子进程子进程则是循环从管道中读取数据等到把管道中的数据读完的时候而父进程又没有关闭它的写端此时子进程的read函数就会进入读堵塞状态等待父进程继续向管道中写入数据父进程已经进入了进程阻塞等待自然不会再向管道中写入数据因此就进入了卡死状态 2.   细心的小伙伴可能会有疑惑父进程只向管道中写入一次数据子进程读取一次就应该将数据读取完了呀子进程循环一次就该进入堵塞而运行结果显示子进程的循环进行了两次呢 这是因为我们使用write函数进行写入时写入的大小是sizeof(test_buff)也就是64个字节而我们用read函数读取数据的时候读取的是sizeof(test_buff)-1也就是63个字节此时管道中还剩一个字节管道并不为空因此read函数还可以读取一次所以循环就进行了两次 3.可能你会想为什么要读取sizeof(test_buff)-1个字节呢一次读完不好吗 这是因为在C语言中有些函数会自动给字符数组的末尾添加/0而有的函数又不会自动添加如果一次读完遇到了末尾自动添加/0的函数就会将末尾的数据给覆盖掉导致数据丢失因此在不能分辨某个字符处理函数是否会自动在字符末尾添加/0的时候为了安全我们统一把字符数组的最后一位给留出来也就是数据只读取字符数组大小-1个 上述的情况是父进程进入阻塞等待时并没有关闭写端导致子进程的read函数误认为父进程还会向管道中写入数据于是就进入阻塞状态一直等待。 4.如果父进程写完了并且关闭了自己的写端呢 如果管道中还有数据那么子进程的read函数会继续读取数据如果管道中没有数据了那么read函数就会返回0不会进入阻塞等待状态因此在循环读取的场景下一定要注意接收read函数的返回值不然会进入死循环的状态的 5.如果父进程往管道中写入的数据很快而子进程读取的速度比较慢的话会出现什么情况呢 我们前面说过管道通信文件是借助文件系统实现的但是管道通信文件跟一般的文件还不太一样管道通信文件不像普通文件一样可以存放到磁盘中管道通信文件不存放到磁盘上和磁盘没有关系且没有inode是操作系统临时分配的一块固定大小的内存我们也称其为管道缓冲区所以当写的速度太快读的速度太慢管道缓冲区被写满的时候此时写方就会进入写入阻塞状态直到缓冲区足够再次容纳写入的数据时才会再次允许写入 6.还有一种场景如果写方还在继续向管道缓冲区写入数据时而读方却关闭了读端那么此时系统就会终止并杀死写端因为读方都已经关闭读端了再写也没有意义了 这样子就引出了四大特殊情况我们下面再说 7.说了这么多貌似并没有解释为什么会叫匿名管道 父子进程之间进行通信时临时创建的这个管道文件并没有对应的文件名和inode只是系统分配的一块内存空间可以以文件的形式被父子进程打开或关闭这一切工作都在不知不觉中由OS全部完成了所以称为匿名管道等命名管道文件看完也可以回头对比着理解 8.现在我们回过头来理解命令ps ajx | grep pid 管道符|用于将一个命令的输出作为另一个命令的输入。在这个命令中ps ajx命令的输出将作为grep pid命令的输入。 当这个命令在shell中执行时shell会创建一个匿名管道。ps ajx命令形成的进程作为管道的写端将其输出写入管道而grep pid命令形成的进程作为管道的读端从管道中读取输入。 因此ps ajx和grep pid都作为shell的子进程通过匿名管道进行通信。ps ajx将其输出写入管道而grep pid从管道中读取数据实现了两个命令之间的通信 4.管道的4中特殊情况  我们看段代码先确定几个事项父子进程读写问题这里我以父进程为写端子进程为读端相反也行。 #includestdio.h #includestring.h #includestdlib.h #includeunistd.h #includesys/stat.h #includesys/wait.h #includesys/types.hvoid writer(int wfd)//写端调用 {const char* str hello father, I am child;char buffer[128];int cnt 0;pid_t pid getpid();while(1){snprintf(buffer, sizeof(buffer), messge:%s, pid: %d, count: %d\n, str, pid, cnt);//向buffer内写入strwrite(wfd, buffer, sizeof(buffer));//通过系统调用对管道文件进行写入cnt;sleep(1);} }void reader(int rfd)//读端调用 {char buffer[1024];while(1){ssize_t n read(rfd, buffer, sizeof(buffer) - 1);//系统文件与C语言没关系所以不算 \0(void)n;//返回值用不到避免警告制造的假应用场景printf(father get a message: %s, buffer);} }int main() {// 创建管道int pipefd[2];int n pipe(pipefd);if(n 0) return 1;printf(pipefd[0]: %d, pipefd[1]: %d\n, pipefd[0]/*reader*/, pipefd[1]/*writer*/);// fork子进程pid_t id fork();if(id 0){// child w端close(pipefd[0]);writer(pipefd[1]);exit(0);}//father r端close(pipefd[1]);reader(pipefd[0]);//通过系统调用 对管道文件读取wait(NULL);return 0; } 我们通过对上面这个代码的不断修改来讲解读写端的四种情况 ①写端进程不写读端进程一直读 还是上述匿名管道测试代码子进程一直在写父进程一直在读子进程写的数据现在我们让子进程等待五秒之后再对管道文件进行写入 那么问题就来了在子进程休眠的这五秒期间父进程在干吗 实际上在子进程休眠的这5秒父进程在等待子进程休眠结束直到子进程再次写入数据时父进程才会读取。 所以我们的 结论 就是管道内部没有数据的时候并且其中的写端不关闭自己的文件描述符时读端就要进行阻塞等待直到管道文件有数据。 ①写端进程不写读端进程一直读那么此时会因为管道里面没有数据可读对应的读端进程会被阻塞挂起直到管道里面有数据后读端进程才会被唤醒。 ②读端进程不读写端进程一直写 第二种情况当写端一直在对管道文件进行写入而读端却不再对管道文件一直执行sleep进行读取我们修改写端接口如下 void writer(int wfd) {const char* str hello father, I am child;char buffer[128];int cnt 0;pid_t pid getpid();while(1){// snprintf(buffer, sizeof(buffer), messge:%s, pid: %d, count: %d\n, str, pid, cnt);//向buffer内写入str// write(wfd, buffer, sizeof(buffer));//通过系统调用对管道文件进行写入char* ch X;write(wfd, ch, 1);cnt;printf(cnt: %d\n, cnt);} } 如果我们编译运行程序我们会发现写端对管道文件一直写入一个字符但是到了第65536个字符时却卡在这里了。 其实这个时候 写端在阻塞这是因为我们写入的对象也就是 管道文件 被写满了从计数器我们可以看出一个管道文件的大小为 65536 个字节ubuntu20.04也就是 64KB 大小 注意管道文件的大小依据平台的不同也各不相同。 所以我们得到的 结论 是当管道内部被写满且读端不关闭自己的文件描述符写端写满之后就要进行阻塞等待 ②读端进程不读写端进程一直写那么当管道被写满后对应的写端进程会被阻塞挂起直到管道当中的数据被读端进程读取后写端进程才会被唤醒。 前面的①②两种情况就能够很好的说明管道是自带同步与互斥机制的读端进程和写端进程是有一个步调协调的过程的不会说当管道没有数据了读端还在读取而当管道已经满了写端还在写入。         读端进程读取数据的条件是管道里面有数据写端进程写入数据的条件是管道当中还有空间若是条件不满足则相应的进程就会被挂起直到条件满足后才会被再次唤醒。 如何理解阻塞挂起 唤醒                 进程先立即停止执行然后将PCB的状态改为阻塞状态并将PCB插入相应的阻塞队列。         当被阻塞进程所期待的事情发生将阻塞进程从阻塞队列中移出将其PCB的状态改为就绪状态(R)然后将PCB插入到就绪队列中.          ③写端进程将数据写完后将写端关闭 当写端对管道文件缓冲区进行了有限次的写入并且把写端的文件描述符关闭而读端我们保持正常读取内容读端多的仅仅把读端的返回值打印出来。 我们发现当10读取执行完成之后就一直在执行读取操作而我们读取使用的 read 接口的返回值却从0变为了1。我们接着用监视窗口来监视一下 当写端写了10个数据之后将文件描述符关闭那么读端进程就会变为僵尸状态。由此我们可以得出read接口返回值的含义 是当写端停止写入并关闭了文件描述符read的返回值为0正常读取的返回值 0。 所以我们可以这样修改读端的代码 void reader(int rfd) {char buffer[1024];while (1){ssize_t n read(rfd, buffer, sizeof(buffer) - 1);if (n 0)printf(father get a message: %s, ret: %ld\n, buffer, n);else if (n 0){printf(read pipe done, read file done!\n);break;}elsebreak;} } 所以我们就能得出 结论 对于读端而言当读端不再写入并且关闭了pipe那么读端将会把管道内的内容读完最后就会读到返回值为0表示读取结束类似于读到了文件的结尾。 ③写端进程将数据写完后将写端关闭那么读端进程将管道当中的数据读完后就会继续执行该进程之后的代码逻辑而不会被挂起。读端进程已经将管道当中的所有数据都读取出来了(读端就会read返回值0代表文件结束)而且此后也不会有写端再进行写入了那么此时读端进程也就可以执行该进程的其他逻辑了而不会被挂起。      ④读端进程将读端关闭而写端进程还在一直向管道写入数据 我们把情况三最后的代码变换一下读端读取改为有次数限制并且读取一定次数之后关闭读的文件描述符而写端无限制对管道文件写入那么我们会看到什么现象呢 而我们发现似乎也没什么不对啊读取完之后不就直接退出了吗 你应该仔细想想我们仅仅是关闭了读的文件描述符但是没有关闭写的文件描述符啊。 这就是最后一个 结论当读端不再进行读取操作并且关闭自己的文件描述符fd而写端依旧在写。那么OS就会通过信号SIGPIPE的方式直接终止写端的进程。 ④读端进程将读端关闭而写端进程还在一直向管道写入数据没有进程读取那么写入的数据就没有意义那么操作系统会将写端进程杀掉。既然管道当中的数据已经没有进程会读取了那么写端进程的写入将没有意义因此操作系统直接将写端进程杀掉。而此时子进程代码都还没跑完就被终止了属于异常退出那么子进程必然收到了某种信号。 管道是单向通信如果读端不读数据且把文件描述符关闭那么写端做的就没有意义了。写端相当于废弃的动作浪费资源所以OS直接将子进程干掉。为什么?OS不做不做任何浪费空间或者低效的事情只要发现OS一定要把这个事情修正了。  如何证明读端是被13号信号杀死的         我们采用的是父进程读子进程写的方式也就是说将来子进程被杀死而父进程则可以通过wait的方式来获取子进程退出时的异常 int status 0; pid_t rid waitpid(id, status, 0);if(rid id) {printf(exit code : %d, exit signal : %d\n, WEXITSTATUS(status), status 0x7F); } 7)使用命令查看信号 kill - l   5.验证管道的大小 管道的容量是有限的如果管道已满那么写端将阻塞或失败需要了解一下管道的大小              ①方法一使用man手册 根据man手册在2.6.11之前的Linux版本中管道的最大容量与系统页面大小相同从Linux 2.6.11往后管道的最大容量是65536字节。 查看Linux系统版本 这里使用的是Linux 2.6.11之后的版本因此管道的最大容量是65536字节。   ②方法二使用ulimit命令 可以使用ulimit -a 命令查看当前资源限制的设定, 管道的最大容量是 512 × 8 4096 字节 ③写代码验证管道容量 根据man手册得到的管道容量与使用ulimit命令得到的管道容量不同测试验证代码概述: 读进程一直不读写进程一直写直到管道被写满  #include unistd.h #include stdio.h #include stdlib.h #include sys/wait.hint main() {int fd[2] { 0 };if (pipe(fd) 0){ //使用pipe创建匿名管道perror(pipe);return 1;}pid_t id fork(); //使用fork创建子进程if (id 0){ //child close(fd[0]); //子进程关闭读端char c .;int count 0;while (1){write(fd[1], c, 1);count;printf(%d\n, count); //打印当前写入的字节数}close(fd[1]);exit(0);}//fatherclose(fd[1]); //父进程关闭写端//父进程不读取数据waitpid(id, NULL, 0);close(fd[0]);return 0; } 在读端进程不进行读取的情况下写端进程最多写65536字节的数据就被操作系统挂起了也就是说我当前Linux版本中管道的最大容量是65536字节  6.管道的特点 ①管道内部自带同步与互斥机制。 我们将一次只允许一个进程使用的资源称为临界资源。管道在同一时刻只允许一个进程对其进行写入或是读取操作因此管道也就是一种临界资源。 临界资源是需要被保护的若是我们不对管道这种临界资源进行任何保护机制那么就可能出现同一时刻有多个进程对同一管道进行操作的情况进而导致同时读写、交叉读写以及读取到的数据不一致等问题。 为了避免这些问题内核会对管道操作进行同步与互斥 同步 两个或两个以上的进程在运行过程中协同步调按预定的先后次序运行。比如A任务的运行依赖于B任务产生的数据。互斥 一个公共资源同一时刻只能被一个进程使用多个进程不能同时使用公共资源。 实际上同步是一种更为复杂的互斥而互斥是一种特殊的同步。 对于管道的场景来说 互斥就是两个进程不可以同时对管道进行操作它们会相互排斥必须等一个进程操作完毕另一个才能操作而同步也是指这两个不能同时对管道进行操作但这两个进程必须要按照某种次序来对管道进行操作。 也就是说互斥具有唯一性和排它性但互斥并不限制任务的运行顺序而同步的任务之间则有明确的顺序关系。         子进程往管道里面写入子进程去读取的时候有数据就拿上来没数据就不在读取而是阻塞式的等待管道数据写入并非父进程sleep了而是因为子进程写的慢父进程必须等而引起好像父进程sleep了这种—个等另一个的现象叫做同步。                                        ②管道的生命周期随进程。 管道本质上是通过文件进行通信的也就是说管道依赖于文件系统那么当所有打开该文件的进程都退出后该文件也就会被释放掉所以说管道的生命周期随进程。 ③管道提供的是流式服务。 我们一般所谓的流式概念就是给你提供一个通信的信道你的写端就直接写读端直接读但是具体写多少读多少完全有上层决定。底层就只是提供一个数据通信的信道就完了它不关心数据本身的一些细节格式这叫做面向字节流。 流式服务 数据没有明确的分割一次拿多少数据都行。数据报服务 数据有明确的分割拿数据按报文段拿。 ④管道是半双工通信的。 在数据通信中数据在线路上的传送方式可以分为以下三种 单工通信单工模式的数据传输是单向的。通信双方中一方固定为发送端另一方固定为接收端。半双工通信半双工数据传输指数据可以在一个信号载体的两个方向上传输但是不能同时传输。全双工通信全双工通信允许数据在两个方向上同时传输它的能力相当于两个单工通信方式的结合。全双工可以同时(瞬时)进行信号的双向传输。 管道是半双工的数据只能向一个方向流动需要双方通信时需要建立起两个管道。 7.管道的读写规则
http://www.zqtcl.cn/news/160336/

相关文章:

  • l礼品文化网站建设不常见的网络营销方式
  • 做网站侵权腾讯企点打不开
  • iis 网站拒绝显示此网页上海网站建设类岗位
  • 营销型网站建设推荐google关键词
  • 网站上线是前端还是后端来做如何做垂直门户网站
  • 网站建设与管理2018海尔集团网站 建设目的
  • ps做网站大小wordpress调用 php文件
  • php网站忘记后台密码江苏网页制作报价
  • 网站模板 哪个好完备的常州网站推广
  • 衡水淘宝的网站建设濮阳市城乡一体化示范区主任
  • 公司网上注册在哪个网站商洛市商南县城乡建设局网站
  • 怎么才能让网站图文展示大连网站建设设计
  • 俱乐部网站 模板seo产品是什么意思
  • 新手学做网站的教学书建造师查询官网
  • win2012 iis添加网站群辉做网站服务器
  • 网站优化课程培训山东网站备案公司
  • top wang域名做网站好事业单位门户网站建设评价
  • 有什么网站可以做简历网站备案表格
  • 网站开发用什么图片格式最好厦门人才网个人会员
  • 关于网站开发的文献深圳网络推广代运营
  • 网站做app的重要性做静态网站有什么用
  • 一键搭建网站系统教做衣服的网站有哪些
  • 城乡建设部网站施工员证书查询中铁建设集团有限公司招标平台
  • 广东省建设项目安全标准自评网站哪个网站可以免费做简历
  • 带产品展示的个人网站模板购物网站开发背景
  • 哪个域名注册网站好seo广告投放是什么意思
  • 网站建设ydwzjs电子邮箱怎么申请
  • 福建省建住房建设部网站wordpress 算数验证码
  • 东莞企业如何建网站网站正在建设中...为什么护卫神
  • 引流用的电影网站怎么做wordpress浏览速度