进程的定义、创建(fork/vfork)及evec函数族详解

一:进程和程序之间的区别

1:程序是静态的,它包括代码段,数据段(栈,普通数据区,堆区);

2:进程是程序的一次运行过程,即运行一次产生一个进程,运行两次产生两个进程;

3:进程存在一些状态的变化,他是动态的;

4:进程不仅包括程序的代码段,数据段内容,还有其他资源(因为要运行这个进程),如:一些系统数据,pc指针;

5:进程管理属于内核层,内核层的主要功能是设备驱动,进程管理,文件管理和网络通信。

二:进程的相关命令:

1:ps

     权限:所有用户

     命令格式:ps[选项]

     功能:查看系统中的进程状态

     eg:ps -axj ;    //运行结果为系统中的进程

2:kill

     权限:所有用户

     命令格式:kill[选项][进程号]

     功能:发送指定的信号给指定的进程或进程组

     常用选项:   -l   :查看有哪些信号,eg:kill -l

                        -9:结束进程(包括后台进程),如:kill -9 pid

三:创建子进程函数fork和vfork

1:fork函数

头文件:#include<sys/types.h>

功能:创建一个子进程

参数:没有参数

返回值:成功返回两个值。子进程中为0;父进程中为大于0 的值(子进程的pid号),出错则返回一个值-1.

成功时,内核为何会返回两个值?

这是因为用户空间的进程可以认为是一个封闭的房子(在用户空间),内核通过PID对用户空间的进程进行管理。fork函数调用成功后,内核则在用户空间创建一个新进程(房子),这个房子和之前的进程代码段,数据段等都一样(除了PID之外)。因此,当函数执行成功时,在父进程和子进程中返回两个不同的值。

产生的子进程在父进程原有的运行基础上继续运行,这样就能保证一个fork函数只能产生一个子进程,而不是多个子进程;

在一个main中若存在n个fork();则最终将产生2^n个进程。

注意:fork函数成功执行后,父进程和子进程的执行没有固定的先后顺序,这是因为CPU在微观上是串行执行,宏观上是并行执行。即CPU在一个时间片里运行一个进程,在另一个时间片里运行另一个进程,从而导致这两个进程交替运行,且运行顺序随机未知。

2:vfork函数

vfork函数也跟fork函数一样。vfork函数执行成功后,内核也在用户空间创建一个进程,但不会重新建造一个房子,父子进程共享父进程这个房子,同时子进程先执行,父进程后运行。

3: fork()与vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别: 

1.  fork  ():子进程拷贝父进程的数据段,代码段 
    vfork ( ):子进程与父进程共享数据段 
2.  fork ()父子进程的执行次序不确定 
    vfork 保证子进程先运行,在调用exec 或exit 之前与父进程数据是共享的,在它调用exec
     或exit 之后父进程才可能被调度运行。 
3.  vfork ()保证子进程先运行,在她调用exec 或exit 之后父进程才可能被调度运行。如果在
   调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。 

四:exec函数族

前面在创建子进程时,子进程进行了代码的完全拷贝,虽然我们用返回值的不同来使得父子进程执行了两个不同的代码区,但是很多情况下,父子进程的代码完全不一样。比如:bash是父进程,a.out是子进程,这两段代码没有相似性;或父进程是C代码,子进程是一个shell脚本的情况,应该怎么处理?

这些,都可以通过exec函数族来解决。

(1)exec函数说明
fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
(2)在Linux中使用exec函数族主要有以下两种情况
a. 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何exec 函数族让自己重生。
b. 如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。
(3)exec函数族语法
实际上,在Linux中并没有exec函数,而是有6个以exec开头的函数族,下表列举了exec函数族的6个成员函数的语法。
所需头文件: #include <unistd.h>
函数说明: 执行文件
函数原型:

[plain]  view plain  copy
  1. int execl(const char *path, const char *arg, ...)  
  2. int execv(const char *path, char *const argv[])  
  3. int execle(const char *path, const char *arg, ..., char *const envp[])  
  4. int execve(const char *path, char *const argv[], char *const envp[])  
  5. int execlp(const char *file, const char *arg, ...)  
  6. int execvp(const char *file, char *const argv[])  

函数返回值:成功 -> 函数不会返回,出错 -> 返回-1,失败原因记录在error中。
这6 个函数在函数名和使用语法的规则上都有细微的区别,下面就可执行文件查找方式、参数表传递方式及环境变量这几个方面进行比较说明。
①    查找方式:上表其中前4个函数的查找方式都是完整的文件目录路径,而最后2个函数(也就是以p结尾的两个函数)可以只给出文件名,系统就会自动从环境变量“$PATH”所指出的路径中进行查找。
②    参数传递方式:exec函数族的参数传递有两种方式,一种是逐个列举的方式,而另一种则是将所有参数整体构造成指针数组进行传递。
在这里参数传递方式是以函数名的第5位字母来区分的,字母为“l”(list)的表示逐个列举的方式,字母为“v”(vertor)的表示将所有参数整体构造成指针数组传递,然后将该数组的首地址当做参数传给它,数组中的最后一个指针要求是NULL。读者可以观察execl、execle、execlp的语法与execv、execve、execvp的区别。
③    环境变量:exec函数族使用了系统默认的环境变量,也可以传入指定的环境变量。这里以“e”(environment)结尾的两个函数execle、execve就可以在envp[]中指定当前进程所使用的环境变量替换掉该进程继承的所以环境变量。

猜你喜欢

转载自blog.csdn.net/leikun153/article/details/79867201
今日推荐