- 1、本文档共27页,可阅读全部内容。
- 2、有哪些信誉好的足球投注网站(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
linux 进程(二) --- 进程的创建及相关api
一、进程的创建fork()函数
由fork创建的新进程被称为子进程(child process)。该函数被调用一次 ,但返回两
次。两次返回的区别是子进程的返回值是0 ,而父进程的返回值则是 新子进程的进
程ID。将子进程ID返回给父进程的理由是 因为一个进程的子进程可以多于一个 ,所
有没有一个函数使一个进程可以获得其所有子进程的进程ID。fork使子进程得到返
回值0的理由是 一个进程只会有一个父进程 ,所以子进程总是可以调用getppid以
获得其父进程的进程ID(进程 ID 0总是由交换进程使用 ,所以一个子进程的进程ID
不可能为0)。
子进程和父进程继续执行fork之后的指令。子进程是父进程的复制品。例如 ,子
进程获得父进程数据空间、堆和栈的复制品。注意 ,这是子进程拥有的拷贝。父、
子进程并共享这些存储部分。如果正文段是只读的 ,则父、子进程共享正文段。
现在很多的实现并不做一个父进程数据段和堆的完全拷贝 ,因为在fork之后经常
跟随着exec。作为替代 ,使用了写时复制(copy-on-write,cow)的技术。这些区域
由父、子进程共享 ,而且内核将他们的存取许可权改变位只读的。如果有进程试图
修改这些区域 ,则内核包异常 ,典型的是虚存系统中的 “页” ,做一个拷贝。
实例1
#include stdio.h
#include stdlib.h
#include unistd.h
int glob = 6;
char buf[] = a write to stdout\n;
int main()
{
int var;
int pid;
var = 88;
if(write(STDOUT_FILENO,buf,sizeof(buf) -1) != sizeof(buf) -1)
{
perror(fail to write);
return -1;
}
printf(before fork\n);
if((pid = fork()) 0)
{
perror(fail to fork);
return -1;
}else
if(pid == 0)
{
glob ++;
var ++;
}else{
sleep(2);
}
printf(pid = %d,glob = %d,var = %d\n,getpid(),glob,var);
exit(0);
}
运行结果
从上面可以看出 ,因为子进程和父进程拥有独立的物理内存空间 ,所以当子进程对
拷贝来的数据做修改的时候 ,并没有影响到父进程。
注意
1.一般来说 ,fork之后父进程先执行还是子进程先执行是不确定的。这取决于
内核所使用的调度算法。
2.从上面可以看到两次的运行结果不一样。我们知道write函数是不带缓存
的。因为在fork之前调用write ,所以其数据写到标准输出一次。但是 ,标准 I/O库
是带缓存的。如果标准输出连到终端设备 ,则它是行缓存的 ,否则它是全缓存的。
当以交互方式运行该程序时 ,只得到printf输出的行一次 ,其原因是标准输出缓存
由新行符刷新。但是当将标准输出重新定向到一个文件时 ,却得到printf输出行两
次。其原因是 ,在fork之前调用了printf一次 ,当调用fork时 ,该行数据仍在缓存
中 ,然后在父进程数据空间复制到子进程中时 ,该缓存数据也被复制到子进程中。
于是那时父、子进程各 自有了带该行内容的缓存。在exit之前的第二个printf将其数
据添加到现存的缓存中。当每个进程终止时 ,其缓存中的内容被写到相应文件中。
实例 2
#include stdio.h
#include stdlib.h
#include unistd.h
int glob = 6;
int main()
{
int var;
文档评论(0)