学科分类
目录
Linux编程

系统调用

系统调用中发送信号常用的函数有kill()、raise()、abort()等,其中kill是最常用的函数,该函数的作用是给指定进程发送信号,但是否杀死进程,取决于所发送信号的默认动作。kill()存在于函数库signal.h中,其函数声明如下:

int kill(pid_t pid, int sig);

若函数调用成功,则返回0;否则返回-1,并设置errno。kill()函数有两个参数:pid表示接收信号的进程的pid,sig表示要发送的信号的编号。参数pid的不同取值会影响kill()函数作用的进程,其取值可分为4种情况,每种取值代表的含义如下:

● 若pid > 0,则发送信号sig给进程号为pid的进程;

● 若pid = 0,则发送信号sig给当前进程所属组中的所有进程;

● 若pid = -1,则发送信号sig给除1号进程与当前进程的所有进程;

● 若pid < -1,则发送信号sig给属于进程组-pid的所有进程。

kill()函数发送信号的对象范围取决于调用kill()函数进程的权限,只有root用户有权发送信号给任一进程,普通用户进程只能向属于同一进程组或同一用户的进程发送信号。参数sig的取值一般为常规信号的编号,当其设置为特殊值0时,kill()函数不发送信号,但会进行错误检查,此时可以根据kill()函数的返回值来判断用户进程是否有权限向另外一个进程发送信号:

● 若返回值为0,表示kill()函数成功调用,当前进程有权限;

● 若返回值为-1,且errno为ESCRCH,表明指定接收信号的进程不存在;否则表示当前进程没有权限。

不同操作系统中信号编号对应的信号名不一定相同,为了提高代码可读性和可移植性,用户在使用kill()函数时应尽量使用系统中定义的宏进行传参。

案例1:使用fork()函数创建一个子进程,在子进程中使用kill()发送信号,杀死父进程。

 1    #include <stdio.h>
 2    #include <stdlib.h>
 3    #include <unistd.h>
 4    #include <signal.h>
 5    int main()
 6    {
 7        pid_t pid;
 8        pid=fork();
 9        if(pid==0){            //子进程
 10            sleep(1);
 11            printf("child pid=%d,ppid=%d\n",getpid(),getppid());
 12            kill(getppid(),SIGKILL);//发送信号SIGKILL给父进程
 13        }   
 14        else if(pid>0){        //父进程
 15            while(1){
 16                printf("parent pid=%d,ppid=%d\n",getpid(),getppid());
 17            }
 18        }   
 19        return 0;
 20    }

为了保证父进程能接收到子进程发送的信号,在父进程执行的代码段中添加循环,保持父进程的运行;子进程的代码段中调用了kill()函数发送SIGKILL信号给父进程,在此之前使子进程先沉睡1秒。编译案例,执行程序,执行结果如下:

……
parent pid=2873,ppid=2672
child pid=2874,ppid=2873
Killed

当终端输出“Killed”时,表明子进程发送的信号SIGKILL成功杀死了父进程。

多学一招:raise()/abort()

除kill()外,raise()、abort()和pause也是常用的系统调用。raise()函数的功能是发送指定信号给当前进程自身,该函数存在于函数库signal.h中,其函数声明如下:

int raise(int sig);

若raise()函数调用成功,则返回0;否则返回非0。其参数sig为要发送信号的编号,使用kill()函数可以实现与该函数相同的功能,该函数与kill()之间的关系如下:

raise(sig==kill(getpid(),sig)

abort()函数的功能是给当前进程发送异常终止信号SIGABRT,终止当前进程,并生成core文件,该函数存在于函数库stdlib.h中,其函数声明如下:

void abort(void);

该函数在调用之时会先解除阻塞信号SIGABRT,然后才发送信号给自己。它不会返回任何值,可以视为百分百调用成功。

pause()函数的作用是造成进程主动挂起,等待信号唤醒。调用该函数后进程将主动放弃cpu,进入阻塞状态,直到有信号递达将其唤醒,才继续工作。pasue()存在于函数库unistd.h中,其函数声明如下:

int pause(void);

pasue()函数的参数列表为空,不一定有返回值。根据唤醒进程信号不同的默认动作,pause()函数可能有以下几种情况:

(1) 若信号的默认处理动作是终止进程,则进程终止,pause()函数没有机会返回;

(2) 若信号的默认处理动作是忽略,进程继续处于挂起状态,pause()函数不返回;

(3) 若信号的处理动作是捕捉,则调用玩信号处理函数后,pause返回-1,并将errno设置为EINTR,表示“被信号中断”;

由以上情况可知,pause()只有错误返回值。另外,需要注意的是,若信号被屏蔽,被pasue()函数挂起的进程无法被其唤醒。

点击此处
隐藏目录