Linux学习之进程通信(信号的发送)

言之者无罪,闻之者足以戒。 ——《诗序》

命令:kill -l   可以查看内核可以发送多少种信号

命令:ps -axj 可以查看进程的状态

信号:

信号通信,其实就是内核向用户空间进程发送信号只有内核才能发信号,用户空间进程不能发送信号

信号通信的框架:

(1)信号的发送(发送信号的进程):kill() 、raise() 、alarm()

(2)信号的接收(接收信号进程):pause()、sleep()、while(1)

(3)信号的处理(接收信号进程):signal()

一、信号的发送(发送信号的处理)

1、kill: 杀死一个进程

所需头文件

#include <signal.h>

#include <sys/types.h>

函数原型 

int kill(pid_t pid, int sig);

函数传入值

pid

正数:要接收信号的进程的进程号

0:信号被发送到所有和pid进程在同一个进程组的进程

-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)

sig:信号

函数返回值

成功:0

出错:-1

下面来看一下代码:

第一个程序:

#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
        int sig;
        int pid;
        if(argc <3)
        {
                printf("please input:\n");
                return -1;
        }
        sig=atoi(argv[1]);
        pid=atoi(argv[2]);
        printf("sig=%d,pid=%d\n",sig,pid);
        kill(pid,sig);
        return 0;
}

第二个程序:

#include <stdio.h>

int main()
{
        while(1);
        return 0;
}

上面的程序实现的就是调用kill()函数来实现杀死正在运行的进程。

2、raise:发送信号给自己

所需头文件

#include <signal.h>

#include <sys/types.h>

函数原型

int raise(int sig);

函数传入值

sig:信号

函数返回值

成功:0

 

出错:-1

下面我们用程序来学习一下这个函数:

include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main()
{
        printf("raise befor\n");
        raise(9);
        printf("raise after");
        return 0;
}

下面用kill()函数和raise()函数来改变进程的状态:

#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
        pid_t pid;
        pid=fork();
        if(pid >0)
        {
                sleep(8);
                if(waitpid(pid,NULL,WNOHANG));
                {
                        kill(pid,9);
                }
                wait(NULL);
                while(1);
        }
        if(pid == 0)
        {
                printf("raise function befoer\n");
                raise(SIGTSTP);
                printf("raise function after\n");
                exit(0);
        }
        return 0;
}

(1)、wait函数:

wait(int *status)

进程一旦调用了wait函数,就会立即阻塞自己,由wait函数自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个这样的子进程出现为止。

参数status用来保护被 收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只是想把这个僵尸进程消灭掉(事实上绝大多数情况我们都是这样的),我们就可以设定这个参数为NULL,

例如:pid=wait(NULL);如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

 (2)、waitpid函数:

pid_t wait(pid_t pid,int *status,int options)

pid :进程的ID,但当pid取值不同时,意义也不同

pid >0:只等待进程ID等于pid的子进程,不管其他已经有多少子进程运行结束退出了,只要指定的子进程还没结束,waitpid就一直等下去。

pid =-1:等待任何一个子进程的退出,没有任何限制,此时waitpid和wait的作用一样

pid=0:等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬

pid< -1:等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值

参数status用来保护被 收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只是想把这个僵尸进程消灭掉(事实上绝大多数情况我们都是这样的),我们就可以设定这个参数为NULL

opion:目前在Linux中只支持WNOHANG和WUNTRACED两个选项,使用WNOHANG参数调用waitpid,即使没有子进程退出,它也会立即返回,不会像wait那样永远等下去。如果两个都不用可以直接写0。

返回值和错误 :

waitpid的返回值比wait稍微复杂一些,一共有3种情况:

1、当正常返回的时候,waitpid返回收集到的子进程的进程ID;

2、如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

3、如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD;

(3)、exit函数

exit()函数关闭所有打开的文件并终止程序。相当于kill(getppid(),17),getppid()返回父进程的标识

exit()函数的参数会被传递给一些操作系统,通常的约定是正常终止的程序传递值0,非正常终止的程序传递非0值

3、alarm:发送闹钟信号的函数

alarm与raise函数的比较:

相同点:让内核发送信号给当前进程

不同点:

(1)alarm只会发送SIGALARM信号

(2)alarm会让内核定时一段时间之后发送信号,raise会让内核立刻发送信号

所需头文件

#include <unistd.h>

函数原型

unsigned int alarm(unsigned int seconds)

函数传入值

seconds:指定秒数

函数返回值

成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则

返回上一个闹钟时间的剩余时间,否则返回0

 

出错:-1

常用信号的处理方式:

信号名

含义

默认操作

SIGHUP

该信号在用户终端连接(正常或非正常)结束时发出,通常是在终端的控制进程结束时,通知同一会话内的各个作业与控制终端不再关联。

终止

SIGINT

该信号在用户键入INTR字符(通常是Ctrl-C)时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程。

终止

SIGQUIT

该信号和SIGINT类似,但由QUIT字符(通常是Ctrl-\)来控制。

终止

SIGILL

该信号在一个进程企图执行一条非法指令时(可执行文件本身出现错误,或者试图执行数据段、堆栈溢出时)发出。

终止

SIGFPE

该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。

终止

SIGKILL

该信号用来立即结束程序的运行,并且不能被阻塞、处理和忽略。

终止

SIGALRM

该信号当一个定时器到时的时候发出。

终止

SIGSTOP

该信号用于暂停一个进程,且不能被阻塞、处理或忽略。

暂停进程

SIGTSTP

该信号用于暂停交互进程,用户可键入SUSP字符(通常是Ctrl-Z)发出这个信号。

暂停进程

SIGCHLD

子进程改变状态时,父进程会收到这个信号

忽略

SIGABORT

该信号用于结束进程

终止

下面给出一段程序:

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main()
{
        int i=0;
        printf("alarm befor\n");
        alarm(8);
        printf("alarm after\n");
        while(i < 20)
        {
                printf("process working time is %d\n",i);
                i++;
                sleep(1);
        }
        return 0;
}

到此为止信号的发文送相关的函数就已经说完了。

猜你喜欢

转载自blog.csdn.net/weixin_42994525/article/details/83042955