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

进程相关的系统调用3

2013-05-11 18:19 141 查看
 

说明:只供学习交流,装载请注明出处

 

一,进程等待:

 

wait函数
头文件

#include <sys/wait.h>

#include <sys/types.h>

函数原型

pid_t wait(int *status);

返回值

成功

失败

是否设置errno

结束的子进程的PID和结束状态

-1

设置

 

参数说明:status用于接收子进程结束返回状态值的参数。如果不关心子进程的返回状态,status可以填NULL。

 

错误信息:

ECHILD:调用wait函数的进程没有任何可以等待的子进程。

 

说明:wait函数返回status状态存在两种情况:一种是子进程正常退出,另一种是接收到了信号而退出。当所有的子进程结束时,wait函数返回最后结束的子进程的PID和结束状态。状态信息被保存在int类型的变量中。对于32位的系统,低16为用于保存状态信息,而高16位被设置为0.具体情况如下表:

 

 

status退出信息
子进程结束情况

第四个字节

第三个字节

第二个字节

第一个字节

正常结束

0

0

退出代码

0

被不能捕捉的信息杀死

0

0

0

接收到的信号值

 

 

 

 

 

为了方便对wait返回的status状态的检查,Linux系统还提供了一些宏,如下表:

宏定义
说明
WIFEXITED(status)

子进程正常退出情况下返回真值(使用exit(3)或_exit(2)或在main中返回)

WEXITSTATUS(status)

返回子进程的退出状态,该宏只应用于WIFEXITED为真的情况(即子进程正常退出的情况)

WIFSIGNALED(status)

子进程被信号终止的情况下返回真值

WTERMSIG(status)

返回导致子进程结束的信号类型,该宏只应用于WIFSIGNALED为真的情况(即子进程被信号终止的情况)

WCOREDUMP(status)

当子进程产生core  dump调试信息时返回真值。注意应用“在#ifdef WCOREDUMP … #endif”的条件编译语句中。

WIFSTOPPED(status)

当子进程接收到停止信号时

WSTOPSIG(status)

返回导致子进程停止的信号类型,该宏只应用于WIFSTOPPED为真值的情况

WIFCONTINUED(status)

子进程接收到信号SIGCONT而继续运行(从Linux2.6.10内核开始)

 

 

二,waitpid函数

头文件

 

#include <sys/wait.h>

#include <sys/types.h>

函数原型

 

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

 

返回值

成功

失败

是否设置errno

返回状态及状态改变的子进程的进程号;如果option使用WNOHANG参数且没有子进程的状态发生改变,则返回0

-1



 

参数说明:

pid:欲等待的子进程进程号:

           pid<-1:等待进程组进程号为pid绝对值的任何子进程。

           pid=-1:等待任何子进程相对于wait()。

           pid=0:等待进程组进程号与目前进程相同的任何子进程。

           Pid>0:等待进程号为pid的指定进程。

status:接收子进程结束返回状态值的参数。如果不关心子进程的返回状态,status可以填NULL。

option:提供了一些额外的选项来控制waitpid:

(1):WNOHANG:如果没有子进程,则退出立即返回。

(2):WUNTRACED:当子进程处于停止状态,则立即返回。

(3):WCONTINUED:当处于停止状态的子进程收到SIGCONT信号后接着运行返回(Linux
2.6.10后的内核支持该参数)。

 

错误信息:

ECHILD:指定进程号的子进程不存在。

EINTR:未设置WNOHANG参数,同时接收到了未阻塞的信号或SIGCHLD信号。

EINVAL:非法的options参数。

 

 

三,kill函数

发送信号给进程,让进程终止运行是进程非正常结束的一种方法。在Linux系统中,定义了64中信号类型。使用“kill –l”

命令可以查看这些信号的具体信息。使用kill命令给知道进程发送信号的命令格式为:kill –信号类型进程号。例如:

Kill –s SIGKILL。

发送的信号有可能被信号捕获,而不会起到默认的作用。例如,发送的SIGTERM信号被进程捕获,导致进程没有按预想结束,为了解决这一问题,Linux提供了SIGKILL信号,这个信号是不会被进程捕获的。也就是说,如果要确保杀死某个进程,可以使用:“kill
–s SIGKILL 进程号”命令。要获得进程的进程号信息可以使用“ps -aux”命令。

 

Linux系统还提供了对应的kill函数,可以在程序开发中实现与kill命令相同的功能。kill函数声明如下:

int kill(pid_t pid, int sig);

pid为将信号发送到的进程号。sig为要发送的信号类型,可以直接使用“kill -l”命令列出的信号类型或直接使用对应的数字。

 

四,僵尸进程

僵尸进程(Zombie Process)是由于子进程退出后父进程没有使用wait函数收集子进程状态而产生的。一个进程在调用exit命令结束自己生命的时候,其他它并没有真正的被销毁,而是留下一个称为僵尸(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果它的父进程没安装SIGCHLD信号处理函数调用wait或waitpid等待子进程结束,由又没有显示忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。由于僵尸进程会占用进程表中的位置,而进程表空间是有限的,Linux系统中产生进程的数量是有限的,过多的僵尸进程会影响新进程的产生。怎么查看僵尸进程,利用命令ps,可以看到有标志为Z的进程就是僵尸进程。
 

僵尸进程的存在是为了给程序员和系统管理员提供一些重要的进程信息。这些信息包括进程如何结束,在运行过程中是否出现了错误等。如果没有僵尸进程,这些信息将随着进程的结束而消失。因此,僵尸进程携带的信息对于程序开发人员和系统管理员发现程序存在问题有着非常重要的意义。

 

一个简单的产生僵尸基础的实例:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>

int main(void)
{
pid_t pid;

pid = fork();

if ( pid < 0 )
{
printf("ERROR!\n");
}
else if (pid > 0)
{
sleep(60);
}
else
{
exit(0);
}
return (0);
}
用 ps –aux可以看到产生了一个僵尸进程:
root     32628  0.0  0.0   1492   264 pts/2    S    20:06   0:00 ./zom
root     32629  0.0  0.0      0     0 pts/2    Z    20:06   0:00 [zom] <defunct>


 

wait实例:

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

int main(void)
{
pid_t pid;

if ((pid = fork())<0)
{
printf("Fork Error: %s\n", strerror(errno));
exit(1);
}
else if (pid == 0)
{
printf("The child process is run\n");
sleep(3);
printf("I am the child: %d\n", getpid());
exit(0);
}
else
{
wait(NULL);
printf("The father process is run\n");
printf("I am the father: %d\n", getpid());
return (0);
}
}


 

waitpid实例:

#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(void)
{
pid_t pid;
int status;
pid = fork();

if (-1 == pid)
{
perror("fork()");
exit(EXIT_FAILURE);
}
else if (0 == pid)
{
puts("In child process");
sleep(10);
printf("child process pid = %d, ppid = %d\n", getpid(), getppid());
exit(EXIT_SUCCESS);
}
else
{
waitpid(pid, &status, 0);
puts("In parent process");
printf("parent process pid = %d, ppid = %d\n", getpid(), getppid());
printf("child process exited with status %d\n", status);
}

exit(EXIT_SUCCESS);
}


 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  应用 Linux C 进程