1:wait
函数功能:父进程一旦调用wait函数,就会立即阻塞自己,由wait分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁返回,如果没有找到,就一直阻塞,直至找到一个结束的子进程或接收到了一个指定的信号为止。
2:waitpid
函数功能:waitpid()的作用和wait()函数一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能等。实际上wait()函数只是waitpid()函数的一个特例。
3:wait()与waitpid()函数的区别:
wait会令调用者阻塞直至某个子进程终止。waitpid则可以通过设置一个选项来设置为非阻塞,另外waitpid并不是等待第一个结束的进程而是等待参数中pid指定的进程。
函数原型:
#include<sys/wait.h>
pid_t wait(int * statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
成功返回进程ID,出错返回0或者-1。
waitpid的option常量:
WNOHANG waitpid将不阻塞如果指定的pid并未结束,
WUNTRACED 如果子进程进入暂时执行情况则马上返回,但结束状态不予理会。
waitpid中pid的含义依据其具体值而变:
pid == -1 等待任何一个子进程,此时waitpid的作用与wait相同。
pid > 0 等待进程ID与pid值相同的子进程。
pid==0 等待与调用者进程组ID相同的任意子进程。
pid<-1 等待进程组ID与pid绝对值相等的任意子进程。
waitpid提供了wait所没有的三个特性:
waitpid使我们可以等待制定的进程。
waitpid提供了一个无阻塞的wait
waitpid支持工作控制
验证wait函数:
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pc, pc1;
pc = fork();
if(pc < 0)
{
printf("error!/n");
}
else if(pc == 0)
{
//sleep(10);
printf("This is child process!/n");
sleep(10);//为了验证wait函数的功能
}
else
{
printf("This is Parent process! /n");
pc1 = wait(NULL);
printf("The child process pid == %d/n",pc1);
}
exit(0);
}
pc1 = wait(NULL);
如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用会失败,
此时wait返回-1.同时errno被置为ECHILD.
有关wait和waitpid函数介绍的好的博客:https://blog.youkuaiyun.com/kevinhg/article/details/7001719
剩余后续更新
3:signal
功能:设置某一信号的对应动作
声明如下:
#include<signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
第一个参数signum:指明所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。
第二个参数handler:描述了与信号关联的动作,它可以取三种类型。
signal的定义原型是:
void (*signal(int signum, void (*func)(int))) (int)
这个函数的最外层的函数体为void(* xxx) (int);表明是一个指针,指向一个函数xxx的指针,XXX所代表的函数需要一个int参数,返回void
signal(int signum, void(*func)(int));
需要两个参数int型的signo以及一个指向函数的指针。正是由于其的复杂性,使用typedef来对其进行简化。
typedef void (*sighandler_t)(int);
所以原函数就可以改为:
sighandler_t signal(int , sighandler_t );
在使用的时候第一个参数代表信号,第二个参数代表接受到这个参数时所需要的进行的操作
对于第二个参数的理解:
(1) SIG_IGN 这个符号表示忽略该信号。
例子:
#include<stdio.h>
#include<signal.h>
int main()
{
signal(SIGINT, SIG_IGN);
while(1);
return 0;
}
SIGINT信号代表有InterruptKey产生,通常是CTRL+C或者DELETE。执行上述代码时,按下CTRL+C程序没有反应。表示该信号被忽略。
(2)SIG_DFL 这个符号表示恢复对信号的系统默认处理。
程序:
#include <stdio.h>
#icnlude <signal.h>
int main()
{
signal(SIGINT, SIG_DFL);
while(1);
return 0;
}
运行程序就可以使用CTRL+C来终止该程序。
(3)sighandler_t类型的函数指针
sighandler_t signal(int signum, sighandler_t handler);
次函数必须在signal()被调用之前申明。当接收到一个类型为sig的信号时,就执行handler所指定的函数。 int signum是传递给它的唯一参数。执行signal()调用后,进程只要接收到类型为sig的信号,不管其正在执行程序的哪一部分,就立即执行handler函数。当handler函数执行结束后,控制权返回进程被中断的哪一点继续执行。
程序:
#include <stdio.h>
#include <signal.h>
typedef void (*signal_handler)(int);
void signal_handler_fun(int signum) {
printf("catch signal %d\n", signum);
}
int main(int argc, char *argv[]) {
signal(SIGINT, signal_hander_fun);
while(1);
return 0;
}
当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。
一些常使用的signal:
Signal | Description |
---|---|
SIGABRT | 由调用abort函数产生,进程非正常退出 |
SIGALRM | 用alarm函数设置的timer超时或setitimer函数设置的interval timer超时 |
SIGBUS | 某种特定的硬件异常,通常由内存访问引起 |
SIGCANCEL | 由Solaris Thread Library内部使用,通常不会使用 |
SIGCHLD | 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略 |
SIGCONT | 当被stop的进程恢复运行的时候,自动发送 |
SIGEMT | 和实现相关的硬件异常 |
SIGFPE | 数学相关的异常,如被0除,浮点溢出,等等 |
SIGFREEZE | Solaris专用,Hiberate或者Suspended时候发送 |
SIGHUP | 发送给具有Terminal的Controlling Process,当terminal 被disconnect时候发送 |
SIGILL | 非法指令异常 |
SIGINT | 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 |
SIGIO | 异步IO事件 |
SIGIOT | 实现相关的硬件异常,一般对应SIGABRT |
SIGKILL | 无法处理和忽略。中止某个进程 |
SIGLWP | 由Solaris Thread Libray内部使用 |
SIGPIPE | 在reader中止之后写Pipe的时候发送 |
SIGPOLL | 当某个事件发送给Pollable Device的时候发送 |
SIGPROF | Setitimer指定的Profiling Interval Timer所产生 |
SIGPWR | 和系统相关。和UPS相关。 |
SIGQUIT | 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程 |
SIGSEGV | 非法内存访问 |
SIGSTKFLT | Linux专用,数学协处理器的栈异常 |
SIGSTOP | 中止进程。无法处理和忽略。 |
SIGSYS | 非法系统调用 |
SIGTERM | 请求中止进程,kill命令缺省发送 |
SIGTHAW | Solaris专用,从Suspend恢复时候发送 |
SIGTRAP | 实现相关的硬件异常。一般是调试异常 |
SIGTSTP | Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程 |
SIGTTIN | 当Background Group的进程尝试读取Terminal的时候发送 |
SIGTTOU | 当Background Group的进程尝试写Terminal的时候发送 |
SIGURG | 当out-of-band data接收的时候可能发送 |
SIGUSR1 | 用户自定义signal 1 |
SIGUSR2 | 用户自定义signal 2 |
SIGVTALRM | setitimer函数设置的Virtual Interval Timer超时的时候 |
SIGWAITING | Solaris Thread Library内部实现专用 |
SIGWINCH | 当Terminal的窗口大小改变的时候,发送给Foreground Group的所有进程 |
SIGXCPU | 当CPU时间限制超时的时候 |
SIGXFSZ | 进程超过文件大小限制 |
SIGXRES | Solaris专用,进程超过资源限制的时候发 |
4:kill
int kill(pid_t pid, int sig);
pid:可能选择由以下四种
1. pid大于零时,pid是信号欲送往的进程的标识
2. pid等于零时,信号将送往所有与调用kill()的那个进程属同一个使用组的进程。
3. pid等于-1时,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
4. pid小于-1时,信号将送往以-pid为组标识的进程。
sig:准备发送的信号代码,假如其值为零则没有任何信号送出,但是系统会执行错误检查,通常会利用sig值为零来检验某个进程是否仍在执行。
返回值说明: 成功执行时,返回0。失败返回-1,errno被设为以下的某个值 EINVAL:指定的信号码无效(参数 sig 不合法) EPERM;权限不够无法传送信号给指定进程 ESRCH:参数 pid 所指定的进程或进程组不存在
代码:
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main( void )
{
pid_t childpid;
int status;
int retval;
childpid = fork();
if ( -1 == childpid )
{
perror( "fork()" );
exit( EXIT_FAILURE );
}
else if ( 0 == childpid )
{
puts( "In child process" );
sleep( 100 );//让子进程睡眠,看看父进程的行为
exit(EXIT_SUCCESS);
}
else
{
if ( 0 == (waitpid( childpid, &status, WNOHANG )))
{
retval = kill( childpid,SIGKILL );
if ( retval )
{
puts( "kill failed." );
perror( "kill" );
waitpid( childpid, &status, 0 );
}
else
{
printf( "%d killed\n", childpid );
}
}
}
exit(EXIT_SUCCESS);
}
5:recv