父子进程读写同一个循环缓冲区 多进程,初始时循环缓冲区 多进程中无数据。

多线程读写同一块缓冲区_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
多线程读写同一块缓冲区
上传于||文档简介
&&多​个​线​程​共​同​讯​写​一​个​数​据​区​,​保​证​数​据​的​完​整​性​,​不​使​作​同​步​信​号​.
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
下载文档到电脑,查找使用更方便
还剩1页未读,继续阅读
你可能喜欢关于fork和缓冲区的问题
题目:请问下面的程序一共输出多少个“-”?
#include &stdio.h&
#include &sys/types.h&
#include &unistd.h&
int main(void)
for(i=0; i&2; i++){
printf(&-&);
一般熟悉fork机制会认为输出为6个'-',但我们运行一下,输出的是8个'-'.
基础知识见上一个题.
&&&程序一开使,bash产生一个进程P1执行此程序,
&&&P1进入程序后,当i=0时,fork()产生一个子进程P2,同时它自己输出一个'-'.
&&&P2继承P1的诸如环境变量,PC等环境,P2首现会输出一个'-'.同时此时i=1,会继续执行for循环---P2先fork()出一个子进程P3,同时再输出一个'-'.
&&&P3进程为P2的子进程,它会复制其父进程P2的指令,变量值,程序调用栈,环境变量,缓冲区等,它会输出一个'-'
&&&&&& 因为这里P3会继承P2的缓冲区,其中有一个'-',所以P3会输出两个'-'.
&&&P1进入程序后,当i=1时,fork()产生另一个它的子进程P4,同时输出一个'-'.
&&&P4同样会输出一个'-'.
&&&&&& 因为P4为P1的一个子进程它会继承P1的缓冲区,其中有一个'-',所以P4会输出两个'-'.
我们正常如上分析觉得应该产生6个'-'.
但为什么是8个呢,見红色部分加上的分析.
这是因为printf(“-”);语句有buffer,所以,对于上述程序,printf(“-”);把“-”放到了缓存中,在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。
如果把上面的printf(&-&)改为
printf(&-\n&);
或着调用fflush清一下缓存.
printf(&-&);
fflush(stdout);
都可以保正输出6个'-'
1. 进程的概念
进程可以理解为程序的一次执行过程。每一个特定的时候只有一个进程占用CPU。
当一个进程的时间片用完后,系统把相关的寄存器的值保存到该进程表相应的表项里。同时把代替该进程即将执行的进程的上下文从进程表中读出,并更新相应的寄存器值,这个过程称为上下文交换。
上下文交换其实就是读出新的进程的PC(程序计数器),指示当前进程的下一条将要执行的指令。
一个进程主要包含以下三个元素:
(1)一个正在执行的程序
(2)与该进程相关联的全部数据(变量,内存,缓冲区)
(3)程序上下文(程序计数器)
2. pid=fork()的创建过程
fork()函数是用来创建子进程的,当一个程序创建了一个子进程,那么原先的进程称为该子进程的父进程。操作系统的进程表的每个表项中存放着一个进程的情况。首先,操作系统在进程表中为该进程建立新的表项。子进程与父进程共享代码段,但数据空间是相互独立的。子进程数据空间的内容是父进程的完整拷贝,上下文也完全相同。pid在父进程与子进程的返回值是不同的,如果pid&0创建失败。在子进程中返回的pid=0,因为子进程可以通过getpid()得到自己的进程ID。在父进程中返回的是子进程的实际的PID。子进程是从fork()之后执行的,此时,父进程与子进程就fork(分道扬镳)了。
(1)子进程copy父进程的变量,内存与缓冲区,即整个的数据空间的内容,但数据空间是独立的。
(2)父子进程对打开文件的共享: fork之后,子进程会继承父进程所打开的文件表,即父子进程共享文件表,该文件表是由内核维护的,两个进程共享文件状态,偏移量等。这一点很重要,当在父进程中关闭文件时,子进程的文件描述符仍然有用,相应的文件表也不会被释放。
<span style="color:#. fork()函数例子
/** 进程的基本操作fork()系统调用 fork()是由父进程创建子进程,并且把父进程的数据结构即上下文复制给子进程 对父进程而言,返回的是子进程的进程ID,即PID,对子进程而言,返回的是0 父进程调用wait函数时阻塞,直到子进程进入僵死状态,这时子进程的退出可通过wait函数返回给父进程,wait常用来判断子进程是否结束 fork()进程的执行过程 一个进程包含三个部分: (1)正在执行的程序 (2)和该进程相关联的全部数据(内存,缓冲区,变量) (3)程序上下文 当父进程fork()之后,创建子进程,为子进程建立一个新的表项,关于子进程的全部信息就保存在这个表项里面了 父进程与子进程共享代码段,但两者的数据段与堆栈段是分区开,子进程数据段的空间内容是从父进程复制而来的 而程序上下文指的是程序计数器PC的位置,即进程执行到了的位置。而在fork()之后就分开执行了,在fork之前,可以看成是两个独立的程序,拥有共同的代码段 在子进程中返回的PID为0,在父进程返回的是子进程的PID,因为在子进程中通过getpid()可以得到子进程的PID. 总之,子进程可以看成是与父进程是并列的两个程序,在fork之后分开执行的。共享代码段,但数据段与堆栈段是分开的,内容是从父进程复制而来的 在C语言中,有以下几种情况会刷新缓冲区: (1)缓冲区满 (2)遇到换行符/n时 (3)第三种调用fflush函数时 (4)程序正常退出,异常退出就不保证了 当printf在fork函数之前,首先父进程执行printf,此时并不输出内容,由于没有/n 。当子进程被fork()之后,子进程的执行起点为fork之后,所以子进程并没有执行printf.但由于子进程复制父进程数据空间,缓冲区的内容,所以父进程的缓冲区被子进程复制了。到这里,父进程继续执行没执行完的部分,子进程执行fork()之后的内容,到程序正常结束后,就是上面所说的第(4)条,首先父进程flush自己的缓冲区,然后子进程flush缓冲区。至于谁先谁后flush决定于操作系统,这样就会打印出两行AAAA了。 总之,printf的确是只执行了一次,输出在最后不一定是/n,有可能是上面几种情况之一。
而printf(&AAAA/n&)则直接刷新缓冲区,输出到终端上。 当父子进程分别打开文件表时,共用文件表的偏移量,状态等信息 因此,在子进程中关闭文件时,父进程照样能用,相应的文件表也不会被释放
#include &stdio.h&
#include &sys/types.h& #include &sys/stat.h& #include &string.h& #include &sys/wait.h& #include &unistd.h& #include &fcntl.h& #include &stdlib.h&
int main(){ pid_//用来保存子进程的PID char buf[100]={0};//定义缓冲区//定义文件标识符 f=open(&text&,O_CREAT|O_RDWR,0664); if(f==-1){//文件标识符 perror(&文件创建失败&); return 1; } strcpy(buf,&父进程数据&); printf(&%d/n&,strlen(buf)); //此时创建子进程 childpid=fork(); printf(&childpid=%d&,childpid); if(childpid==0){ strcpy(buf,&子进程数据&); printf(&%s/n&,buf); puts(&子进程正在工作&); printf(&子进程的PID是%d/n&,getpid()); printf(&父进程的PID是%d/n&,getppid()); int n1= write(f,buf,strlen(buf));//把buf的数据输出重定向到文件中去,strlen是返回字符串的长度,而sizeof返回的是类型所占空间的大小,前面是个函数,后面是一个操作符,sizeof是编译时求值,而strlen是运行时求值 strcpy(buf,&子进程数据&); write(f,buf,strlen(buf)); close(f); exit(0);//子进程调用exit函数进入僵死状态,参数0表示正常退出 }
else { puts(&父进程正在工作&); printf(&%s/n&,buf); printf(&父进程的PID是%d/n&,getpid()); printf(&子进程的PID是%d/n&,childpid); int n=write(f,buf,strlen(buf)); close(f); }
wait(&status);//wait函数是一个等待子进程退出的函数,其参数是一个int类型的指针,保存子进程退出的一些信息
return 0; }
程序运行结果如下:
15 & //父进程打印出来的 childpid=0子进程数据 子进程正在工作 子进程的PID是7271 父进程的PID是7270 childpid=7271父进程正在工作 父进程数据 父进程的PID是7270 子进程的PID是7271
如果把 printf(&%d/n&,strlen(buf)); 改为printf(&%d&,strlen(buf)); ,那么运行的结果为:
15childpid=0子进程数据 &//这个15是子进程打印出来的 子进程正在工作 子进程的PID是7284 父进程的PID是7283 15childpid=7284父进程正在工作 父进程数据 父进程的PID是7283 子进程的PID是7284
1. wait()函数阻塞父进程,直到子进程返回。因此,子进程先执行,直到退出为止。
为什么printf(&%d/n&,strlen(buf)); 与 printf(&%d&,strlen(buf));打印的结果不相同?
printf(&%d/n&,strlen(buf)); 与 printf(&%d&,strlen(buf)); 区别:
前者将数据已经输出到终端上了,后者的数据还在缓冲区内。
当创建子进程时,子进程要copy父进程的数据,包括copy缓冲区,所以,第一个程序只打印出一个15,而第二个程序打印出两个15.
还要注意一点,第一个结果的15是由父进程打印出来的,而第二个结果由于子进程先执行,复制缓冲区,所以子进程先打印出15,而后父进程才打印出15.
2. close(f),当子进程已经关闭了文件,父进程怎么还能将数据写入?
&在前面的分析中得知,父子进程共享同一个文件表,共享文件表的状态,偏移位置等信息。所以在子进程关闭文件描述符后,在父进程中仍然是有效的,而父进程写数据也从文件的当前位置开始写。
而linux系统文件流,缓冲及文件描述符与进程之间的关系,可参考http://topic.csdn.net/u//3aba9e11-c8a8-492b-9fe7-.html
总之,父子进程是共享代码段的,但数据空间是分开的,而子进程数据空间的内容是来自父进程的copy,这些copy包括变量,缓冲区,内存。另外,父子进程共享同一文件表,当在一个进程中关闭文件时,在另一个进程中仍然是有效的,相应的文件表不会被释放。
本分类共有文章78篇,更多信息详见
& 2012 - 2014 &
&All Rights Reserved. &
/*爱悠闲图+*/
var cpro_id = "u1888441";
/*爱悠闲底部960*75*/
var cpro_id = "u1888128";进程通信01_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
进程通信01
上传于||暂无简介
大小:1.94MB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢进程读写实验说明_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
进程读写实验说明
上传于||文档简介
&&进&#8203;程&#8203;读&#8203;写&#8203;实&#8203;验&#8203;说&#8203;明
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
下载文档到电脑,查找使用更方便
还剩1页未读,继续阅读
你可能喜欢实验六 进程间通信_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
实验六 进程间通信
上传于||暂无简介
大小:258.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢

我要回帖

更多关于 父子进程通信 的文章

 

随机推荐