linux调度fork进程,进程调度: Linux fork()你知道多少

from http://blog.163.com/huww_vip/blog/static/185913087201151153625168/

2011.06

我们先说说函数原型:

头文件:

#include

函数定义:

int fork( void );

返回值:

子进程中返回0,父进程中返回子进程ID,出错返回-1

函数说明:一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间,它们之间共享的存储空间只有代码段。

示例代码:

#include

#include

int main(int argc, char ** argv )

{

int pid = fork();

if(pid == -1 )

{

// print("error!");

} else if( pid = =0 ) {

// print("This is the child process!");

} else

{

// print("This is the parent process! child process , pid);

}

return 0;

}

Fork()系统在Linux中的返回值是没有NULL的.

Error Codes

出错返回错误信息如下:EAGAIN

达到进程数上限.ENOMEM没有足够空间给一个新进程分配。

呵呵呵,要理解了,这些还远远不够的,你知道在Linux系统下,fork()是关键,下面多说一些:

第一点就是:

操作系统对进程的管理,是通过进程表完成的.进程表中的每一个表项,记录的是当前操作系统中一个进程的信息.进程在系统的唯一标识是PID,PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号.当用完32768后,从2重新开始.

.一个称为“程序计数器(program counter, pc)”的寄存器,指出当前占用 CPU的进程要执行的下一条指令的位置.当分给某个进程的 CPU时间已经用完,操作系统将该进程相关的寄存器的值,保存到该进程在进程表中对应的表项里面,把将要接替这个进程占用 CPU的那个进程的上下文,从进程表中读出,并更新相应的寄存器.

第二点就是:vfork()

vfork与fork主要有三点区别:

.fork():子进程拷贝父进程的数据段,堆栈段;vfork():子进程与父进程共享数据段.fork()父子进程的执行次序不确定vfork 保证子进程先运行,在调用 exec 或 exit 之前与父进程数据是共享的,在它调用 exec或 exit 之后父进程才可能被调度运行。

.vfork()保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

1)先用fork()进行试验

#include

#include

int main(void)

{

pid_t pid;

int count=0;

pid=fork();

count++;

printf("count= %d\n",count);

return 0;

}

分析:

通过上面fork()的说明,这个程序的输出应该是:

./test

count= 1

count= 1

2)而将fork()换成vfork()呢,程序如下

#include

#include

int main(void)

{

pid_t pid;

int count=0;

pid=vfork();

count++;

printf("count= %d\n",count);

return 0;

}

执行结果:

./test

count= 1

count= 1

Segmentation fault (core dumped)

分析:

通过将fork()换成vfork(),由于vfork()是共享数据段,为什么结果不是2呢,答案是:

vfork保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁.

3)做最后的修改,在子进程执行时,调用_exit(),程序如下:

#include

#include

#include

int main(void)

{

pid_t pid;

int count=0;

pid=vfork();

if(pid==0)

{

count++;

_exit(0);

}

else

{

count++;

}

printf("count= %d\n",count);

return 0;

}

执行结果:

./test

count= 2

分析:如果子进程中如果没有调用_exit(0),则父进程不可能被执行,在子进程调用exec(),exit()之后父进程才可能被调用.

所以加上_exit(0),使子进程退出,父进程执行.

这样 else 后的语句就会被父进程执行,又因在子进程调用 exec 或 exit 之前与父进程数据是共享的,

所以子进程退出后把父进程的数据段 count 改成1了,子进程退出后,父进程又执行,最终就将count 变成了 2.

简要的概括的说是:

1)fork()系统调用是创建一个新进程的首选方式,fork的返回值要么是0,要么是非0,父进程与子进程的根本区别在于fork函数的返回值.

2)vfork()系统调用除了能保证用户空间内存不会被复制之外,它与fork几乎是完全相同的.vfork存在的问题是它要求子进程立即调用exec,

而不用修改任何内存,这在真正实现的时候要困难的多,尤其是考虑到exec调用有可能失败.

3)vfork()的出现是为了解决当初fork()浪费用户空间内存的问题,因为在fork()后,很有可能去执行exec(),vfork()的思想就是取消这种复制.

4)现在的所有unix变量都使用一种写拷贝的技术(copy on write),它使得一个普通的fork调用非常类似于vfork.因此vfork变得没有必要.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值