在学进程通信的时候接触到了下面这段代码

#include<stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>int main()
{//create pipeint fd[2]={0,0};if(pipe(fd)!=0){//create falseperror("pipe");exit(1);}// pipe create successpid_t id=fork();if(id==0){//child -->write fd[1]printf("Child\n");sleep(2);const char* msg="Hello,leap\n";close(fd[0]);int count=3;while(count--){ssize_t size=write(fd[1],msg,strlen(msg));printf("size:%d\n",size);//if(count--){//  sleep(1);//}sleep(1);printf("child is writing...\n");}close(fd[1]);exit(0);}else{//father -->read fd[0]printf("Father\n");sleep(2);close(fd[1]);char buf[1024];int count=3;while(1){ssize_t Len=read(fd[0],buf,1024);//printf("Len::%d\n",Len);printf("Father is reading...\n");if(Len>0){//read successbuf[Len]='\0';printf("child say:%s",buf);}else if(Len==0){//read end of fileprintf("Read the end of pipe\n");break;}else{perror("read");exit(1);}}close(fd[0]);int status=0;pid_t _pid=waitpid(id,&status,0);if(_pid==id){printf("Wait success for child\n");printf("Exit code:%d,Exit signal:%d\n",(status>>8)&0xff,status&0xff);}else{perror("wait");}exit(0);}return 0;
}
————————————————
版权声明:本文为CSDN博主「_stark」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/bit_clearoff/article/details/55105816

这段代码里有不少的sleep函数,以前使用sleep函数都是为了扩大一下程序运行的时间来对比各种算法的时间复杂度。这是第一次在OS里面接触到sleep函数,这里的sleep函数显然是针对进程来进行的。意识到以前一直忽略了一个问题,就是fork函数创建的子进程与父进程执行的顺序究竟是怎样的.在网上寻找了一下,没有找到答案。于是写了以下的程序进行测试:

#include <stdio.h>
#include <unistd.h>int main(){pid_t t = fork(),count=100;while(count--){if(t == 0){printf("son\n");}else{printf("father\n");}}return 0;
}

运行的结果是前半段是是father,中间是father和son交替出现,后面是son。
那么猜测的结果应该是他们是并发进行的,只不过son进程进入执行状态的时间会稍微慢一点。所以才会出现中间交替出现的情况。
那么上面那段代码里的sleep函数可以这么理解,首先是父进程先执行,执行到第一个sleep函数后挂起,进入到子进程之后又有一个sleep(2),理论上来说和父亲休眠的相同的时间后应该是父亲先进入执行状态,结果运行的结果却是下面这样:

可以发现的是先进入到了子进程处,此处产生了很大的疑惑,在网上找寻不到答案也不知道如何正确描述问题,目前只能强行认为是此时运行的子进程的优先级比较高,在多个进程sleep同样的时间的时候优先运行当前正在运行的进程。然后执行子进程的下一个sleep函数,这时才转移到父进程。
上面只是本人不负责任的推理。关于这段代码的疑惑还存在几个重要的问题待解决:

  1. 这个sleep函数到底是如何运行的?为何父进程先挂起了2ms子进程后挂起2ms但最后还是子进程先执行?
  2. 多进程之间的执行顺序又是如何?是和那个测试程序一样多进程之间一个进程读取一行代码吗?

还有一个更神奇的问题时当这段代码执行多次之后,运行顺序将会变得混乱起来。有时reading会在size上面,有时size又会在reading上面,但是进程之间的通信却没有被打扰,父进程依然能正常的接受到子进程的消息。也就是说正在执行的子进程还是优先于父进程执行的。

目前的OS学习刚刚起步,希望这些问题在之后的学习中能得到解决。

update:
事实证明在写程序之前应该先去阅读一下原理。上述的其实是一个很简单的问题,就是管道对于读写端控制的问题。为了让问题更清晰,我们来看下面这段代码。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>int main(){int fd[2] = {0,0};if(pipe(fd) != 0)exit(-1);pid_t id = fork();if(id == -1)exit(-1);if(id == 0){ // sonclose(fd[0]); // 关闭读端,父子进程之间的管道端都是独立的,这个只是单向关闭了子进程的读端。for(int i = 1;i <= 3; ++ i){printf("I'm writing....\n");char msg[20] = "This is x time write"; // 使用char*定义的数组无法通过下标更改数组的值。msg[8] = i + '0';write(fd[1],msg,strlen(msg));sleep(30); // 等待父亲读取。}close(fd[1]);exit(0);}else{ // fathersleep(2);close(fd[1]);char msg[1024];int cnt = 0;while(1){printf("%d\n",++cnt);ssize_t length = read(fd[0],msg,1024); // if(length < 0)exit(-1);else if(length == 0){printf("done!");break;}else{msg[length] = '\0';printf("father:%s\n",msg);sleep(2);}}close(fd[0]);}return 0;
}

这是代码的运行结果:

在这个程序里我将sleep函数的时间设定到了30s,有一个客观事实是父子进程确实是并发进行的。那么为什么程序没有在sleep的时间中因为父进程读不到数据而结束?其实很简单,pipe创建的管道为我们提供了阻塞机制。当某个进程要在管道中读取数据时,如果此时管道是空的但又还有写端未关闭时,系统会使用堵塞机制堵塞掉read语句,直到管道中有数据可以读取的时候,read语句才会正确执行。相同的是,如果写端写入数据的时候管道满了,write语句同样会被挂起。

Linux 关于fork函数和sleep函数以及通信管道的一些思考相关推荐

  1. 转:linux中fork()函数详解

    转:linux中fork()函数详解 https://blog.csdn.net/jason314/article/details/5640969 转载于:https://www.cnblogs.co ...

  2. Linux进程5:exec族函数(execl, execlp, execle, execv, execvp, execvpe)总结及exec配合fork使用

    exec族函数(execl, execlp, execle, execv, execvp, execvpe)及exec配合fork使用 exec族函数函数的作用: 我们用fork函数创建新进程后,经常 ...

  3. Linux中fork()函数详解

    Linux中fork()函数详解 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事, ...

  4. linux fork 函数,Linux的fork()系统调用

    Linux的fork()系统调用,就是以父进程为模版创建子进程,是Linux系统的进程管理机制的核心API之一,另一个是调度器函数schedule(),它的用户态API就是之前说自旋锁时提到的sche ...

  5. linux中fork函数与vfork函数的区别

    fork函数跟vfork函数一样能够创建进程,它们主要有两个区别 (1)区别一: vfork直接使用父进程存储空间,不拷贝. (2)区别二: vfork保证子进程先运行,当子进程调用exit退出后,父 ...

  6. linux execl函数 errno,过程控制 Linux C fork() execl() exit() wait()

    进程控制 Linux C fork() execl() exit() wait() 进程控制实验: 在linux下面使用c语言利用系统调用fork(), execl(), exit(), wait() ...

  7. Linux中wait()函数及waitpid()函数

    编程过程中,有时需要让一个进程等待另一个进程,最常见的是父进程等待自己的子进程,或者父进程回收自己的子进程资源包括僵尸进程.这里简单介绍一下系统调用函数:wait() 函数原型是 #include & ...

  8. #includeunistd.h存在linux中,含有系统服务的函数

    #include<unistd.h> linux标准库#include <unistd.h>与windows的#include <windows.h>(C语言开发) ...

  9. linux系统调用:exit()与_exit()函数详解【转】

    (转自:https://blog.csdn.net/drdairen/article/details/51896141) exit()就是退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示 ...

最新文章

  1. 图解 SQL 里的各种 JOIN
  2. Zookeeper 3.5启动时 8080端口被占用
  3. 短信发送的流程,硬编码在了服务方法里面,优化方案
  4. centos web 访问mysql_Centos7安装Web服务器--Mysql5.7.12安装
  5. 腾讯移动分析+html5,FAQ · 腾讯移动分析 文档
  6. 大数据_MapperReduce_协处理器_类似Mysql的触发器---Hbase工作笔记0024
  7. 什么样的公司值得加入?
  8. 个人笔记-Nginx学习常见错误
  9. PDF编辑器中文版怎么插入PDF空白页面
  10. python 爬虫抓取网页数据导出excel_Python实现抓取网页生成Excel文件的方法示例
  11. xmind思维导图怎么把字体变大_XMind 使用指南 | 让思维导图放大你的影响力
  12. 怎么在GIF动态图中添加文字
  13. 【Unity3D基础教程】给初学者看的Unity教程(零):如何学习Unity3D
  14. vector BLF 文件读写
  15. 图论:图的四种最短路径算法
  16. 使用@Aspect不起作用
  17. virtualbox E_INVALIDARG (0x80070057) 和 E_FAIL (0x80004005) SessionMachine
  18. Leet code链表相关题目初探
  19. 便宜耐用学生蓝牙耳机哪款好?适合学生购买的蓝牙耳机推荐
  20. Python open函数打开文件路径

热门文章

  1. hotmail收不到邮件_将Hotmail和实时电子邮件帐户添加到Outlook 2010
  2. 有必要给孩子买台灯吗?分享四款高品质的护眼台灯
  3. 【Vue前端开发学习】第2章,Vue项目目录结构
  4. Java-----IO流【字节缓冲输出、输入流】
  5. 《征途》是怎样赚钱的? .
  6. mac os 安装win8.1后BootCamp 控制面板无法设置触摸板
  7. chatGPT的应用场景
  8. HMI-28-【运动模式】给速度表添加数字显示
  9. 小白第一次注册机编写,c/bat/易某言(不好意思说2333)
  10. MFC实战篇——提示框随鼠标移动动态响应