进程相关函数(一)

1.fork()函数

#include <unistd.h>

pid_t fork(void);

fork函数用于创建子进程,调用一次,返回两次。子进程返回0,父进程返回子进程的ID,调用失败返回负。一般来说,fork后子进程和父进程的执行次序不确定。

子进程与父进程共享正文段(即C程序中由CPU执行的指令部分)和同一个文件偏移量,不共享数据段(初始化数据段)、bss段(未初始化的数据)、栈和堆,子进程拥有不共享部分的副本。父进程中所有打开文件的文件描述符均被复制到子进程中。

子进程继承父进程的组ID、会话ID、控制终端、当前工作目录、资源限制、信号屏蔽和安排、未决信号、文件权限屏蔽字等属性。子进程不继承父进程的进程时间、设置的文件锁等。

2.exec函数族

exec函数族是以新的进程去代替原来的进程,但进程的PID保持不变。因此,可以这样认为,exec系统调用并没有创建新的进程,只是替换了原来进程上下文的内容。原进程的代码段,数据段,堆栈段被新的进程所代替。

linux环境下,exec函数族共用6个函数,一般只有execve是内核的系统调用,其他5个都是库函数,均调用execve

execl(const char* filepath,const char* arg1,char*arg2......,(char *)0)

execlp(const char*filename,const char*arg1,const char*arg2....., (char *)0)

execle(const char*filepath,const char*arg1,const char*arg2,....., (char *)0,char* cons envp[])

execv (const char* filepath,char* argv[])

execvp (const char* filename,char* argv[])

execve (const char* filepath,char*argv[],char* const envp[])

其中l表示list即逐个列举,与v互斥,v表示传入参数列表。p表示path,即函数取filename为参数且从环境变量PATH中寻找可执行文件,e表示environment,即函数采用传入指定的环境变量,而不是采用系统默认的环境变量。

exec调用举例如下:

char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};

char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};

execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);

execv("/bin/ps", ps_argv);

execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);

execve("/bin/ps", ps_argv, ps_envp);

execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);

execvp("ps", ps_argv);

在使用exec函数族时,一定要加上错误判断语句。因为exec很容易执行失败,其中最常见的原因有:

找不到文件或路径,此时errno被设置为ENOENT

数组argvenvp忘记用NULL结束,此时errno被设置为EFAULT

没有对应可执行文件的运行权限,此时errno被设置为EACCES

对打开文件的处理与每个描述符的exec关闭标志值有关,进程中每个文件描述符有一个 exec关闭标志(FD_CLOEXEC),若此标志设置,则在执行exec时关闭该描述符,否则该描述符仍打开。除非特地用fcntl设置了该标志,否 则系统的默认操作是在exec后仍保持这种描述符打开,利用这一点可以实现I/O重定向。

3.exit()_exit()函数

进程正常终止的方式有:从main函数return;调用exit;调用_exit_Exit;最后一个线程从其启动例程返回;从最后一个线程调用pthread_exit

进程非正常终止的方式:调用abort;收到一个信号;

return是语言级的,返回调用函数,而exit是系统调用级的,表示进程退出。 在main函数中return一个整型值与用该值调用exit是等价的。

exit立即调用exit系统调用进入内核,直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构。而exit则先执行一些清理处理,最大区别在于exit()函数在调用exit系统调用前要检查文件的打开情况,把文件缓冲区中的内容写回文件(如printf未输出换行符前的缓存在调用_exit后会被清空从而无法输出,而使用exit则会输出)。然后再返回内核。_Exit_exit

所需头文件: exit: #include<stdlib.h>

_exit: #include<unistd.h>

函数原型:exit: void exit(int status)

_exit: void _exit(int status)

函数传入值:status 是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束;其他的数值表示出现了错误,进程非正常结束。

4.waitwaitpid

#include<sys/types.h>

#include<sys/wait.h>

4.1 pid_t wait (int * status);

wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。

如果在调用 wait()时子进程已经结束,wait()会立即返回子进程结束状态值。

子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回。

如果不在意结束状态值,则参数 status 可以设成 NULL。如果执行成功则返回子进程识别码(PID) ,如果有错误发生则返回返回值-1。失败原因存于 errno 中。status中存的是子进程的结束状态;可用WEXITSTATUSstatus)得到子进程的exit(3)的状态,那么就是3

4.2 pid_t waitpid(pid_t pid,int * status,int options);

waitpid等待IDpid的子进程结束

参数 pid 为欲等待的子进程识别码,其他数值意义如下:

pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。

pid=-1 等待任何子进程,相当于 wait()

pid=0 等待进程组识别码与目前进程相同的任何子进程。

pid>0 等待任何子进程识别码为 pid 的子进程。

参数 option 可以为 0 或下面的 OR 组合:

WNOHANG 如果没有任何已经结束的子进程则马上返回, 不予以等待。

WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。


子进程的结束状态返回后存于 status,底下有几个宏可判别结束情况:

WIFEXITED(status)如果子进程正常结束则为非 0 值。

WEXITSTATUS(status)取得子进程 exit()返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。

WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真

WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。

WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为真。一般只有使用 WUNTRACED 时才会有此情况。

WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先用 WIFSTOPPED 来判断后才使用此宏。

如果执行成功则返回子进程识别码(PID) ,如果有错误发生则返回返回值-1。失败原因存于 errno 中。

posted @ 2015-08-13 17:40  vvi3  阅读(196)  评论(0)    收藏  举报