computer_knowledge_notes/Languages/CLang/libraries/signal.md

4.6 KiB
Raw Blame History

概述

处理信号。信号是发给进程或线程的异步通知。信号源产生信号,内核接收到信号,然后内核把信号发给对应的进程或线程。

使用kill -l查看信号值和信号名。使用man 7 signal查看信号的详细信息。

信号集信号的集合是一个64位的数据类型(因为一共有64种信号一位代表一个信号)。1已注册0未注册。

抵达(delivery):当进程收到信号后所做的动作。抵达有三种:

  • 忽略此信号。
  • 捕获此信号并执行一个特殊函数handler。
  • 执行信号的默认行为。

未决(pending):信号被阻塞。

信号屏蔽状态字(signal mask)在PCB的结构体中每位对应一个信号。1屏蔽0不屏蔽。

信号未决状态字(mask of pending signals)在PCB的结构体中每位对应一个信号。1未决0不抵达。

信号

#define	SIGHUP		1	// 挂起(当进程的控制进程死亡时向进程发送此信号)
#define	SIGINT		2	// 中断(当键盘中断发生时控制终端向进程发送此信号)
#define	SIGKILL		9	// 立即终止进程(此信号不能被捕获或忽略)
#define	SIGTERM		15	// 要求进程终止

相关数据结构

union sigval {          /* Data passed with notification */
	int     sival_int;         /* Integer value */
	void   *sival_ptr;         /* Pointer value */
};

/* 很多API使用sigevent结构体来描述向进程通知一个事件的方式 */
struct sigevent {
	int          sigev_notify; /* 通知的实现方式 */
    		// SIGEV_NONE - 空的通知,即事件到达时不做任何事情
    		// SIGEV_SIGNAL - 通过发送sigev_signo里定义的信号来通知进程
    		// SIGEV_THREAD - 通过调用sigev_notify_function来通知进程
    		// SIGEV_THREAD_ID - 仅POSIX计时器使用详见timer_create(2)
	int          sigev_signo;  /* 信号的编号 */
	union sigval sigev_value;  /* Data passed with notification */
	void       (*sigev_notify_function) (union sigval);
                            /* Function used for thread
                               notification (SIGEV_THREAD) */
	void        *sigev_notify_attributes;
                            /* Attributes for notification thread
                               (SIGEV_THREAD) */
	pid_t        sigev_notify_thread_id;
                            /* 线程id */
};

管理信号

typedef void (*sighandler_t)(int);

/*
 * 作用把信号signum设置给handler处理。
 * 库里定义了三个假的handler
 *   SIG_ERR错误返回。
 *   SIG_DFL默认动作。即关于此信号的默认动作将会执行。
 *   SIG_IGN忽略信号。
 */
sighandler_t signal(int signum, sighandler_t handler);

操作信号集

/* 将信号集set初始化为空即将所有位都设置为0
 * 返回值0成功-1出错。
 */
int sigemptyset(sigset_t *set);

/* 将信号集set初始化为包含所有信号即将所有位都设置为1
 * 返回值0成功-1出错。
 */
int sigfillset(sigset_t *set);

/* 把信号signum添加到信号集set里。即将信号集里对应的位设置为1。
 * 返回值0成功-1出错。
 */
int sigaddset(sigset_t *set, int signum);

/* 把信号signum从信号集set中删除。即将信号集里对应的位设置为1。
 * 返回值0成功-1出错。
 */
int sigdelset(sigset_t *set, int signum);

/* 判断信号signum是否在信号集set里
 * 返回值1包含0不包含-1信号无效
 */
int sigismember(const sigset_t *set, int signum);

/* 挂起调用线程直到信号集set里某个信号变成pending的状态
 * 返回值0代表成功正数是错误号代表失败。
 */
int sigwait(const sigset_t *set, int *sig);

检测或改变信号屏蔽字

/*
 * 作用:获取或改变调用线程的信号屏蔽字。只能用于单进程单线程。
 * howSIG_BLOCK把参数set中的信号添加到信号屏蔽字中
 *      SIG_SETMASK把信号屏蔽字设置为参数set中的信号
 *		SIG_UNMASK从信号屏蔽字中删除参数set中的信号
 * set信号集。
 * oldset如非NULL则保存之前的信号屏蔽字。
 * 返回值0成功,-1失败。
 */
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int rt_sigprocmask(int how, const kernel_sigset_t *set,
                  kernel_sigset_t *oldset, size_t sigsetsize);
/* 作用和sigprocmask一样不同之处在于它适用于多线程程序 */
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);

其它

/* 给线程发信号 */
int pthread_kill(pthread_t thread, int sig);