Linux信号量补充2020-12-14

学习来源:https://www.bilibili.com/video/BV1FE411i7KP?p=6

1. &
&
2. core 文件
core 文件
3. 捕获函数的过程
PC会记录📝 断开的地址,执行完函数之后回到这个地方;如果 return,就是走在捕获函数某个地方绕回去了,不走完;如果 exit 就是正常中断,断掉。
4. 让非正常退出变为正常退出

SIGINT (ctrl+c), SIG(ctrl+/) 这种退出是非正常退出。
如果要将异常终止转为正常终止,需要用 exit()

printf 后面没有 \n 也可以读出来

exit()可以刷新"标准io" 缓存,将没有写入的数据全部读到内核中去。

fflush()

补充:
atexit() : 注册终止函数 即main执行结束后调用的函数
https://www.cnblogs.com/hanxiaoyu/p/5618882.html

  1. atexit 注册多个进程终止处理函数,先注册的后执行(先进后出,和栈一样)
  2. atexit() 用于注册函数结束后所执行的函数
  3. return、exit和_exit的区别:returnexit 效果一样,都是会执行进程终止处理函数,但是用_exit终止进程时并不执行atexit注册的进程终止处理函数。
typedef void (*sighandler_t)(int);

void signal_fun1(int signum)
{
    printf("SIGINT singnum=%d\n", signum);
    exit(-1);
}
void process_exit(void)
{
    printf("After main()\n");
}
int main()
{
    sighandler_t ret = NULL;

    ret = signal(SIGINT, SIG_IGN);
    ret = signal(SIGINT, SIG_DFL);
    ret = signal(SIGINT, SIG_DFL);
    ret = signal(SIGINT, signal_fun1);
    if (ret == SIG_DFL)
    {
        printf("default");
        printf("ret = %p\n", ret);  //都是0 x 0
    }
    else if (ret == SIG_IGN)
    {
        printf("ignore");
        printf("ret = %p\n", ret);
    }
    else if (ret == SIG_ERR)
    {
        printf("error");
        printf("ret = %p\n", ret);
    }
    else
    {
        printf("capture");
        printf("ret = %p\n", ret); //只有这个有地址
    }

    atexit(process_exit);
    while (1)
        ;
    return 0;
}
先打印 default 然后走 signal_fun() 里面的 exit() 正常退出,最后把 注册的 「终止函数」 打印出来
5.自己查 man signal 来接收该函数的返回值
man signal 查看
跟着文档提示走:1,先定义一个 sighandler_t 函数指针类型 2. 设置为 NULL 3. 读文档发现返回值是返回上一次的处理方式 4. 一层层打开ret,总会打印上一次的
6. pkill 和 kill 的不同
不用查 pid 杀几次
7. 一些信号需要记一记
名称 编号 意义
SIGTERM 15 kill pid 直接 默认终止 ,没写 15
SIGQUIT 3 ctrl+\ 终止(和ctrl+c区别,有core文件产生)
SIGPOLL 轮询事件
SIGBUS 硬件故障
SIGIO 异步通知信号
SIGPIPE 写 没有读权限的管道
SIGSEGV 无效存储访问 (segment fault段错误)
8. KILL保底操作,两个信号忽略不了

SIGKILL SIGSTOP

9. 默认值
10. 父子进程的继承

fork之前
父进程设置的处理方式是忽略默认 时,exec 加载新程序后,忽略和默认设置依然有效。
这个新的new_pro就和子进程一样。

子进程变名字了!对信号的忽略和默认不变

父进程设置的处理方式是捕获exec 加载新程序后,子进程就只能是默认。

11. 手动重启 调用 pause(), sleep()

当休眠函数不希望被信号打断时,可以重启这个函数的调用。

查看手册才能确定 pause() 的返回值,从而可以重启
man 3 pause --- 查看手册加一个 3
从上面手册可以看到,只要不 errno,永远返回 -1
sleep
12. 信号集

意思:所有信号62个集合到一起。假如用一个long来存储,它有62位,每一位代表一个信号。在linux中,它的类型是sigset_t,大小是 64bits。

此时你应该又有疑问了:为何是64bits?原因很简单,因为目前linux流行版本一共有64个信号(不同版本信号格式不同),我们一个bit来表示一种信号,一共只需要64bits就行啦!!!

我们想让有些信号屏蔽,有些信号打开。
通过位运算,我们可以把某一位(某个信号) 设置成 1 或者 0

而这些位运算,我们用一组函数就可以实现了:

使用函数sigprocmask() 阻塞信号的传递,只是延迟信号的到达。信号会在解除阻塞后继续传递。

举个🌰:

void handler(int signo)
{
    printf("hello\n");//如果不加\n会在三秒后一起打出
    sleep(3);
    printf("world\n");
    return;
}
int main()
{
    signal(SIGINT, handler);
    while (1)
        ;
    return 0;
}
先出现hello,然后中间sleep 3秒,按多次没有用,因为此时是阻塞的,但是会被记录在 未处理信号集
void handler(int signo)
{
    int ret;
    sigset_t mask, oldset;
    printf("SIG_INT respond:%d\n", signo);
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    ret = sigprocmask(SIG_UNBLOCK, &mask, &oldset);
    sleep(3);
    printf("ret=%d\n", ret);
    return;
}
int main()
{
    signal(SIGINT, handler);
    while (1)
        ;
    return 0;
}

信号的阻塞就是让系统暂时保留信号留待以后发送。由于另外有办法让系统忽略信号,所以一般情况下信号的阻塞只是暂时的,只是为了 防止信号打断敏感的操作。

当然,SIGKILLSIGSTOP 是不能被屏蔽的 ❌ 。

再举个 🌰 :

我们设计一段代码,她让当前进程屏蔽SIG_USR1,而不屏蔽SIG_USR2
然后,我们用kill命令分别向这个进程发送这两个信号,观察现象

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <setjmp.h>
 
void sig_usr_new(int signo);
 
int main(){
    //1,注册信号
    if(signal(SIGUSR1, sig_usr_new) == SIG_ERR)
    {
        printf("can't catch SIGUSR1 !\n");
        exit(1);
    }
 
    if(signal(SIGUSR2, sig_usr_new) == SIG_ERR)
    {
        printf("can't catch SIGUSR2 !\n");
        exit(1);
    }
 
    //2, 修改信号屏蔽字
    sigset_t sigset;
 
    //2.1 初始化sigset
    if (sigemptyset(&sigset) < 0)
    {
        printf("sigemptyset error !\n");
        exit(1);
    }
 
    //2.2 添加要屏蔽的信号
    if (sigaddset(&sigset, SIGUSR1) < 0)
    {
        printf("add SIGUSR1 error!\n");
        exit(1);
    }
 
    //2.3 修改当前信号屏蔽字
    if (sigprocmask(SIG_BLOCK, &sigset, NULL) < 0)
    {
        printf("can't block SIGUSR1!\n");
        exit(1);
    }
 
    //3,死循环,为了防止进程退出
    while(1){
        pause();
    }
}
 
void sig_usr_new(int signo)
{
    printf("received SIGUSR, signo = %d\n",signo);
}
可以看出来 SIGUSR2 才就收到了信号 📶 , 而 SIGUSR1 没有反应被屏蔽掉了!

再来个🌰:

void handler(int signum)
{
    printf("SIG_INT respond:%d\n", signum);
    return;
}

int main()
{
    char tmp = 'a';
    sigset_t bset; //用来设置阻塞的信号集

    sigemptyset(&bset);       //清空信号集
    sigaddset(&bset, SIGINT); //将SIG_INT信号添加到信号集中

    if (signal(SIGINT, handler) == SIG_ERR) //注册安装处理函数
        perror("signal err:");

    sigprocmask(SIG_BLOCK, &bset, NULL); //阻塞SIG_INT信号

    while (tmp != 'q')
    {
        tmp = getchar();
    }
    sigprocmask(SIG_UNBLOCK, &bset, NULL); //解锁阻塞

    pause();
    return 0;
}
之所以打两遍是,第一个 ctrl+c 被暂停到了后面解锁后打印出来。所以 sigprocmask 是 「暂停延迟」不是忽略
发多次也只补发一个👌

注意 ⚠️ :不同系统可能命名不一样,有些是 SIG_ERR, 有些是 SIGINT,有些是-USR1。根据编译出错试着改下其他命名。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,607评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,239评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,960评论 0 355
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,750评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,764评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,604评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,347评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,253评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,702评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,893评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,015评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,734评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,352评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,934评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,052评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,216评论 3 371
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,969评论 2 355

推荐阅读更多精彩内容