Linuxc编程之信号

写这篇博客只是在梳理这几天我看到知识。

LinuxC编程比较难,以前没有接触过操作系统理论,不是正统的计算机专业出身。看书看着看着就忘了,这是我第2次看《LinuxC编程一站式学习》。看第一遍的时候,思维混乱,过目就忘。

所以这回,我借写博客,边看边整理知识体系,以便能真正的记住。


信号中的两个概念:

1、信号递达(Delivery):执行信号的处理叫信号递达。

2、信号未决(Pending):信号从产生到递达之间的状态。


信号的产生,大致分为4类:

1、用户终端按某些按钮之后会产生某些信号。如按下ctrl+c后会产生SIGINT信号。

2、硬件异常产生某些信号。由于某些条件使得硬件检测时通知内核,然后内核向当前进程发送适当的信号。如当前进程访问非法地址时,MMU会发生异常,内核会将这个异常

解释为SIGSEGV信号发送给当前进程。

3、进程调用kill函数将信号发送个另一个进程。

4、当内核检测到某软件条件发生时通过信号通知进程,如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。


信号的处理(不按系统默认的动作处理信号,调用sigaction函数告诉内核处理信号),可选的动作有3种:

1、忽略此信号。

2、执行该信号的默认动作。

3、提供一个信号处理函数,内核在处理该信号时切换到用户执行这个处理函数。

--------------------------------------------------------------------------------------------------------------------

调用系统函数向进程发送信号

kill函数可以给一个指定的进程发送制定的信号。

raise函数可以给当前进程发送制定的信号(自己给自己发送信号)。

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
成功返回0,错误返回-1.
abort 函数使当前进程接收到 SIGABRT 信号而异常终止。
#include <stdlib.h>
void abort(void);
abort 函数总是会成功的,所以没有返回值。

-------------------------------------------------------------------------------------------------------------------

由软件条件产生信号

alarm函数设定一个闹钟,告诉内核在指定的秒数后给当前进程发送一个SIGALRM信号。该信号的默认处理动作是终止当前进程 。

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

函数的返回值是0或者以前设定的闹钟时间剩下的秒数。

如果seconds值为0,则表示取消闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数。



-------------------------------------------------------------------------------------------------------------------

信号的阻塞(Block)

进程可以选择阻塞某种信号。

被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。

阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种动作。

每个信号都有两个标志位分别表示阻塞和未决,还有一个函数指针表示动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达菜清除该标志。


如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?
常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。

----------------------------------------------------------------------------------------------------------------

信号集:信号集时用来描述信号的集合,linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。

用结构体sigset_t表示,sigset_t为

typedef struct{

unsigned long sig[_NSOG_WORDS];

}sigset_t;

在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞。
未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。


信号集操作函数
sigset_t 类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖
于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作 sigset_t 变量,而不应该对它
的内部数据做任何解释。
#include <signal.h>
int  sigemptyset(sigset_t *set);
int  sigfillset(sigset_t *set);
int  sigaddset(sigset_t *set, int signo);
int  sigdelset(sigset_t *set, int signo);
int  sigismember(const sigset_t *set, int signo);
函数 sigemptyset 初始化 set 所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何
有效信号。
函数 sigfillset 初始化 set 所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括
系统支持的所有信号。
在使用 sigset_t 类型的变量之前,一定要调用 sigemptyset 或 sigfillset 做初始化,使信号集处于确定的状
态。
初始化 sigset_t 变量之后就可以在调用 sigaddset 和 sigdelset 在该信号集中添加或删除某种有效信号。
这四个函数都是成功返回0,出错返回-1。

sigismember 是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包
含则返回0,出错返回-1。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
函数sigprocmask可以读取或更改进程的信号屏蔽字。
返回值:若成功则为0,若出错则为-1.
    如果oset为非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。
    如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。
    如果 oset 和 set 都是非空指针,则先将原来的信号屏蔽字备份到 oset 里,然后根据 set 和 how 参数更改信号屏蔽字。
假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值