Linux下的 fork 函数

之前只是了解到linux中的fork函数是用来创建进程,并没有太多的去学习,这里学习记录如下。

撰写不易,转载需注明出处: 本文来自 【jscese】的博客!

定义:

来自百科的解释:fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

通俗的来理解,就是程序跑到fork的时候,进行了一次分身,然后两个基本基本相同的家伙都会独立的接着往下跑.

原型:pid_t fork( void);返回值:

这里的pid_t 是一个宏,由一系列的types.h文件定义后,实际是int类型 而一次调用fork函数是会有两次返回,一次是调用进程的返回,一次是新建进程的返回. 上面说到调用到fork的时候,在fork当中就会进行“分身”,资源状态的复制,所以创建的新进程也是停留在fork函数当中的,调用fork函数的进程可以称做父进程,新建的为子进程.

fork返回值: 父进程就会返回创建的子进程的进程ID. 子进程刚刚被创建,并没有子进程,所以直接返回 0. 如果出错返回负数 .

fork出错可能有两种原因: 1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。 2)系统内存不足,这时errno的值被设置为ENOMEM。

实现:

而fork函数的定义是在/usr/include/unistd.h中有定义,实际调用时是通过系统调用. 在kernel源码中的unistd.h中可以找到这样的宏定义:

#define __NR_fork 1079#ifdef CONFIG_MMU__SYSCALL(__NR_fork, sys_fork)#else__SYSCALL(__NR_fork, sys_ni_syscall)#endif /* CONFIG_MMU */

继续跟进systemcall的实现可以看syscalls.h以及sys_arm.c,分别看下sys_fork的定义和实现:

/* Fork a new task – this creates a new program thread. * This is called indirectly via a small wrapper */asmlinkage int sys_fork(struct pt_regs *regs){#ifdef CONFIG_MMUreturn do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);(-EINVAL);#endif}

可以看到实际上是调用了一个 do_fork 的函数.这才是fork 被系统调用进的接口.

继续看下这个do_fork函数,实现是在kernel源码下的/kernel/fork.c(3.1.10):

/* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */long do_fork(unsigned long clone_flags,unsigned long stack_start,struct pt_regs *regs,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr){struct task_struct *p; // 而这个task_struct结构体即是Linux中对一个进程的描述符…p = copy_process(clone_flags, stack_start, regs, stack_size,child_tidptr, NULL, trace);//这里进行copy复制 代码段,数据段,BSS段,堆,栈等所有用户空间的信息}

上面只是简单的追踪了一下fork的实现,特别是 系统调用 以及 进程资源复制 都是比较复杂的,我接触不多,这里暂时放下,后续有机会去学习.

使用:

作为函数使用,自然离不开代码,下面附上我自己写的一个小测试:

main(int argc,char* argv[]){printf(“begain parent process pid ==%x \n”,getpid());pid_t ipid1=fork();if(ipid1==0){ printf(“first child process pid==%x ,parent process pid==%x \n”,getpid(),getppid());}else{printf(“first fork child process pid==%x ,parent process pid==%x\n”,ipid1,getpid());}pid_t ipid2=fork();if(ipid2==0){ printf(“second child process pid==%x ,parent process pid == %x \n”,getpid(),getppid());}else{printf(“second fork child process pid==%x ,parent process pid==%x\n”,ipid2,getpid());}printf(“========================================= \n”);sleep(1);}

gcc编译运行之后结果如下:

begain parent process pid ==36fd first fork child process pid==36fe ,parent process pid==36fdfirst child process pid==36fe ,parent process pid==36fd second fork child process pid==36ff ,parent process pid==36fd========================================= second fork child process pid==3700 ,parent process pid==36fe========================================= second child process pid==36ff ,parent process pid == 36fd ========================================= second child process pid==3700 ,parent process pid == 36fe =========================================

可以看到最开始main进程的PID是 36fd ,第一次 fork之后,上面有说到是会返回两个值的,并且都会继续往下执行代码段(两份相同的代码,并不共享数据).

如果困难是堵砖墙,拍拍它说你还不够高。

Linux下的 fork 函数

相关文章:

你感兴趣的文章:

标签云: