我们先前学过用fork() vfork()
来创建进程,在OS中提到过对于进程的调度绝大多数都是根据他的优先级进行判断的,是不定的。但是,在vfork函数中,确提到必须先让子进程先运行完,父进程才能运行,着实有点让人费解?其实,这与该函数的实现有关。对于fork 和 vfork 实现,都是基于调用do_fork 函数,其实
还有一个函数clone。也是用来创建进程的。
他们三者的区别:(clone_flag)
fork : 对于用户空间(中的资本资源)是进行复制的。
vfork:对于用户空间通过指针全部进行共享。
clone :根据传递的参数,来判断哪些进行共享,哪些进程复制。
对于vfork函数来讲clone_flag 的值为: SIGCHILD|CLONE_VFORK前一个信号表示子进程死亡之后要给父进程发一个信号,而一个表示vfork因为,对于vfork函数来讲,父子进程的用户空间完全共享,因此无论谁对用户空间数据的修改对于双方都是可见,更加严重的是,在子函数的调用中会用到
栈,父子进程最后可能因为访问越界而死亡。因此,必须只能让一个进程在用户空间能运行。直到它死亡或者父子进程之间的用户空间不再共享为止。如果,父进程先死亡,那么,子进程便会变成孤儿进程(最后由init进程接管)。对于有些程序是不合理的。所以先扣留‘父进程’,让子进程先运行。
而对于该过程是通过信号量进行实现的。
在do_fork开始的地方申请了一个变量将其赋给了currnet-> vfork_sem
变量。并且他的值为0。
current->vfork_sem = DECLARE_ MUTEX_LOCKED( sem
)
#define DECLARE_MUTEX(name) __DECLARE_SEMAPTHORE_GENERIC(name
,1) 通常信号量的值为1
#define DECLARE_ MUTEX_LOCKED( name )
__DECLARE_SEMAPTHORE_GENERIC(name ,0)
但是current->vfork_sem的值为0,因此只要父进程执行一次down()操作就会进入睡眠状态而达到被扣留的目的。
@
在do_fork()函数尾部有关于clone_flags 中 VFORK的判断。如果是,调用down函数
if (( & ) && ( > 0))
(&);
@
直到执行up()操作被唤醒。
up操作:如果进程执行execve则是在真正意义上与父进程的“分道扬镳”。在装载可执行文件的时候,会创建自己的用户空间,此时会通过
mm_release()函数来判断,如果此进程是通过vfork()创建的,会执行up操作。
因此如果使用了vfork()函数,子进程需要调用函数exit()进行退出。否则可能出现下列错误:
cxa_atexit.c:100: __new_exitfn: Assertion `l != ((void *)0)' failed.
已放弃
阅读(1233) | 评论(0) | 转发(0) |