Android C++系列:Linux信号(二)

简介: 如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非 空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针, 则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前 的信号屏蔽字为mask,下表说明了how参数的可选值。

PCB的信号集


如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允 许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只 计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本文不讨论实时信 号。每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少 次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t 来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态, 在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有 效”和“无效”的含义是该信号是否处于未决状态。


阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解 为阻塞而不是忽略。


sigprocmask


调用函数sigprocmask可以读取或更改进程的信号屏蔽字。


#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
返回值:若成功则为0,若出错则为-1


如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非 空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针, 则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前 的信号屏蔽字为mask,下表说明了how参数的可选值。


how参数的含义


  • SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set
  • SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
  • SIG_SETMASK设置当前信号屏蔽字为set所指向的值,相当于mask=set


如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前, 至少将其中一个信号递达。


sigpending


#include <signal.h>
int sigpending(sigset_t *set);


sigpending读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则 返回-1。


下面用刚学的几个函数做个实验。程序如下:


#include <signal.h> 
#include <stdio.h>
void printsigset(const sigset_t *set) {
  int i;
  for (i = 1; i < 32; i++)
    if (sigismember(set, i) == 1) 
      putchar('1');
    else 
    putchar('0');
  puts("");
}
int main(void) {
  sigset_t s, p;
  sigemptyset(&s);
  sigaddset(&s, SIGINT); 
  sigprocmask(SIG_BLOCK, &s, NULL); 
  while (1) {
    sigpending(&p); 
    printsigset(&p); 
    sleep(1);
    }
  return 0; 
}


程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,按Ctrl-C将会使SIGINT信号处于 未决状态,按Ctrl-\仍然可以终止程序,因为SIGQUIT信号没有阻塞。


qingkouwei@ubuntu:~$ ./a.out 
0000000000000000000000000000000 
0000000000000000000000000000000(这时按Ctrl-C) 
0100000000000000000000000000000 
0100000000000000000000000000000(这时按Ctrl-\) Quit (core dumped)


信号捕捉设定


![image-20211123131623665](/Users/shenjunwei/Documents/Doc/vegetable/source/_note/编程语言/写给Android开发的C++教程/_v_images/Android C++系列:Linux信号(二)/image-20211123131623665.png)


#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction 定义: 
struct sigaction {
  void (*sa_handler)(int);
  void (*sa_sigaction)(int, siginfo_t *, void *);
  sigset_t sa_mask;
  int sa_flags; 
  void (*sa_restorer)(void);
};


  • sa_handler : 早期的捕捉函数
  • sa_sigaction : 新添加的捕捉函数,可以传参 , 和sa_handler互斥,两者通过sa_flags选择采用哪种捕捉函数
  • sa_mask : 在执行捕捉函数时,设置阻塞其它信号,sa_mask | 进程阻塞信号集,退出捕捉函数后,还原回原有的 阻塞信号集
  • sa_flags : SA_SIGINFO 或者  0
  • sa_restorer : 保留,已过时


举例SIGINT被捕捉: 当前进程从内核返回用户空间代码前检查是否有信号递达,有则去响应


利用SIGUSR1和SIGUSR2实现父子进程同步输出


注意:子进程继承了父进程的信号屏蔽字和信号处理动作


总结


如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允 许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只 计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。

目录
相关文章
|
2月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
98 0
|
2月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
106 1
Linux C/C++之IO多路复用(aio)
|
1月前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
110 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
2月前
|
Ubuntu Linux 编译器
Linux/Ubuntu下使用VS Code配置C/C++项目环境调用OpenCV
通过以上步骤,您已经成功在Ubuntu系统下的VS Code中配置了C/C++项目环境,并能够调用OpenCV库进行开发。请确保每一步都按照您的系统实际情况进行适当调整。
503 3
|
2月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
33 0
Linux C/C++之线程基础
|
2月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
36 0
Linux C/C++之IO多路复用(poll,epoll)
|
2月前
|
网络协议 Linux 网络性能优化
Linux C/C++之TCP / UDP通信
这篇文章详细介绍了Linux下C/C++语言实现TCP和UDP通信的方法,包括网络基础、通信模型、编程示例以及TCP和UDP的优缺点比较。
48 0
Linux C/C++之TCP / UDP通信
|
2月前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
41 0
Linux c/c++之IPC进程间通信
下一篇
DataWorks