您的位置:首页 > 运维架构 > Linux

Linux基础学习系列:对于fork()函数的学习,及进程创建相关知识

2010-10-23 13:44 876 查看
fork()函数


:由当前进程再生成一个进程出来

#include <sys/types.h>



#include <unistdh>



pid_t fork(void);



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

大于0表示运行在父进程当中,等于0表示运行再子进程当中

/**********************************************************************/

注:获取进程标识

#include <sys/types.h>


#include <unistd.h>


pid_t getpid(void); //返回:调用进程的进程ID


pid_tgetppid(void); //返回:调用进程的父进程ID


/**********************************************************************/

由fork创建的新进程被称为子进程(child process)。

该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是子进程的进程ID。
将子进程
I D

返回给父进程的理由是:因为一个进程的子进程可以多于一个,所以没有一个函数使一个进程可以获得其所有子进程的进程
I D


f o r k

使子进程得到返回值
0

的理由是:一个进程只会有一个父进程,所以子进程总是可以调用
g e t p p i d

以获得其父进程的进程
I D (

进程
ID 0

总是由交换进程使用,所以一个子进程的进程
I D

不可能为
0 )



一般来说,再fork()函数运行之后,是父进程先执行还是子进程先执行是不确定的。这取决于内核所使用的调度算法。

使用fork()函数得到的子进程从父进程处继承了整个进程的地址空间,包括:进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设置、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等。

f o r k
有两种用法:


(1)

一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待委托者的服务请求。当这种请求到达时,父进程调用
f o r k

,使子进程处理此请求。父进程则继续等待下一个服务请求。

(2)

一个进程要执行一个不同的程序。这对
s h e l l

是常见的情况。在这种情况下,子进程在从
f o r k

返回 后立即调用
e x e c



父、子进程之间的区别:


1.fork()函数的返回值

2.进程ID

3.子进程的tms_utime, tms_stime, tms_cutime以及tms_ustime设置为0,即子进程的进程控制块(PCB)中时间相关参数设置为0

4.父进程设置的锁,子进程不继承

5.子进程的未决告警被清除

6.子进程的未决型号集设置为空集

例程:

#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
pid_t reuslt ;
result = fork();
if(result == -1)
{
perror("fork");
exit;
}
else if(result==0)
{
printf("The return value is %d/nIn child process!/nMy PID is %d/n",result,getpid());
}
else
{
printf("The return value is %d/nIn father process!/nMy PID is %d/n",result ,getpid());
}
}


运行结果:

The return value is 9479

In father process!

My PID is 9478

The return value is 0

In child process!

My PID is 9479

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

vfork()函数


一般来说arm7和arm9的板子上运行的操作系统不太一样,arm7的是ucLinux,而arm9是Linux
,后者

有一个MMU


vfork()函数就是对ucLinux来说的
。为什么要用vfork()函数呢,因为其对内存的申请做了一些优化
。首先其参数和返回值与fork()是一样的,只是两种的运行过程稍有不同,仅复制父进程的一些主要内容,并不是完全拷贝父进程的数据段和堆栈段,而使用写时复制技术(Copy—on—Write,COW),即仅修改时才做复制备份工作。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

exec()函数


fork过来的子进程和父进程一模一样,是没有任何意义的,这时就要用到exec函数族(这里代表了一系列函数)。就是说fork()产生一个子进程,只是提供了一个运行空间,具体运行哪个程序,现在还没有定,最后由exec()以便去执行另外一个程序,有点类似于“金蝉脱壳”的感觉。之所以要安排两步建立进程,是为了在fork之后但在exex之前允许该子进程处理其文件描述符,这样可以完成对标准输入、标准输出和标准出错的重定向。

当进程调用一种exec()函数时,该进程完全由新程序代替,而新程序则从其main()函数开始执行。因为调用exec()并不创建新进程,所以前后进程ID并未改变,exec只是用另一个程序替换了当前进程正文、程序、堆和栈段。

int execl(char *pathname, char *arg0, arg1, ..., argn, NULL);
int execle(char *pathname, char *arg0, arg1, ..., argn, NULL,char *envp[]);
int execlp(char *pathname, char *arg0, arg1, .., NULL);
int execple(char *pathname, char *arg0, arg1, ..., NULL,
char *envp[]);
int execv(char *pathname, char *argv[]);
int execve(char *pathname, char *argv[], char *envp[]);
int execvp(char *pathname, char *argv[]);
int execvpe(char *pathname, char *argv[], char *envp[]);


上述函数名中:l代表链表,v代表矢量(vector),e代表环境变量,p代表自动搜索相关系统路径(path)


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
if(fork() == 0)
{
if(execlp("ps", "ps", "-ef", NULL) < 0)
{
perror("execlp error!");
}
}
return 0;
//这里因省略起见,没有加入一些出错调试语句
}




转载我博客文章郑重声明:技术性网站著名原创作者即可转载,商业性网站必须经过我的同意才能转载,否则追究责任——

**pang123hui的博客:

**

**CSDNhttp://blog.csdn.net/pang123hui/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: