Linux编程基础 4.1:信号学习之系统调用

1简介

信号:软中断信号,是软件层次上对中断的一种模拟,用于提醒进程事件的发生。
可以从两个方面来理解信号:
从生活方面:
你在网上购买了一个商品,等待快递到了之前,你可以去做自己的事情。

  • 进程:你自己;
  • 操作系统:快递员
  • 信号:快递到达的消息

操作系统给进程发生一个信号,进程收到信号后,知道怎么去处理这个信号。(快递员给你发送快递到达的消息,你收到这个消息后,安排时间去取快递

从技术层面:
当运行一个前台进程,按下ctrl + c组合键时,进程会退出。
在这里插入图片描述
当按下ctrl + c 时,产生了一个硬件中断,被操作系统获取到,然后系统发送了一个信号给前台进程。前台进程收到信号后,退出了进程。

用户比较容易控制的信号发送方式有:

  • 组合按键方式;
  • Shell命令方式;
  • 系统调用:kill、raise、abort等。

本部分主要以系统调用为主。

2 系统调用

2.1 kill函数

#include <signal.h>
int kill(pid_t pid, int sig);

函数功能

  • 给指定进程,是否杀死进程取决于所发送信号的默认动作。

参数说明

  • pid:接收信号的进程id
    – pid > 0:发送信号sig给进程pid;
    – pid = 0:发送信号sig给当前进程所属组中的所有进程;
    – pid = -1:发送信号sig给除1号进程与当前进程外的所有进程;
    – pid < -1:发送信号sig给属于进程组pid的所有进程。
  • sig:发送的信号编号

返回值

  • 0: 表示kill函数调用成功,当前进程有权限;
  • -1且errno为ESRCH:表示指定接收信号的进程不存在;
  • -1且errno不为ESRCH:当前进程没权限。

【案例 1】创建一个子进程,在子进程中用kill发送信号,杀死父进程。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

int main() {
    pid_t tempPid;

    tempPid = fork();

    if(tempPid == 0){//child
        sleep(1);
        printf("Child pid = %d, ppid = %d\n", getpid(), getppid());
        kill(getppid(), SIGKILL);
    } else if(tempPid > 0) { //parent
        while(1){
            printf("parent pid = %d, ppid = %d\n", getpid(), getppid());
        }//of while
    }//of if

    return 0;
}//of main

补充知识:查看系统定义的信号,每一个信号都有一个编号和一个宏定义名称,1 ~ 31为普通信号,34 ~ 64为实时信号。
在这里插入图片描述

2.2 其它函数

#include <signal.h>
int raise(int sig);

函数功能

  • 给当前进程发送指定信号。
  • raise(sig) == kill(getpid(), sig)

参数说明

  • sig:发送的信号编号

【案例2】

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>

int main(int argc,char* argv[]){
	sleep(5);
	printf("等待5s后自杀\n");
	raise(SIGKILL);
	while(1);
	return 0;
}//of main

结果:
haitu@ubuntu:/opt/linux_test/signal/signal1$ ./arise 
等待5s后自杀
已杀死

#include <stdlib.h>
void abort(void);

函数功能

  • 给当前进程发送异常终止信号SIGABRT,终止当前进程并生成core文件。
  • 该函数在调用之时会先解除对信号SIGABRT的阻塞,然后发送信号给自己。

该函数无参数无返回值:视为百分百调用成功。

【案例3】

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>

int main(int argc,char* argv[]){
	sleep(5);
	printf("等待5s后自杀\n");
	abort();
	while(1);
	return 0;
}//of main

结果:
haitu@ubuntu:/opt/linux_test/signal/signal1$ ./abort 
等待5s后自杀
已放弃 (核心已转储)
#include <unistd.h>
int pause(void);

函数功能

  • 造成进程主动挂起,等待信号唤醒。
  • 调用该函数后进程将主动放弃CPU,进入阻塞状态,直到有信号将其唤醒,才继续工作。

该函数无参数。

返回值

  • 若信号的默认处理动作是终止进程,则进程终止,pause函数没有机会返回;
  • 若信号的默认处理动作是忽略,进程继续处于挂起状态,pause函数不返回;
  • 若信号的默认处理动作是捕获,则调用完信号处理函数后,pause函数返回-1,并将errno设置为EINTR,表示“被信号中断”。

【案例4】

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
 
int main() {
    printf("Press Ctrl+C to stop the pause.\n");
    pause(); // 进程会在这里暂停,直到接收到一个信号
    printf("Received signal, continuing...\n");
    return 0;
}

当运行这段代码时,进程会在 pause() 调用处暂停,等待任何信号。当用户按下 Ctrl+C(通常会发送 SIGINT 信号),pause 调用会被信号处理函数中断,程序会继续执行,打印出 “Received signal, continuing…”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HenrySmale

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值