[1]sigqueue(发送信号)
int sigqueue(pid_t pid, int sig, const union sigval value);
参数: pid: 要发送信号的进程ID
sig: 要发送的信号
value: 发送的伴随数据,该参数的数据类型是联合体
union sigval {
int sival_int;
void *sival_ptr; // 几乎不用(每个进程都有独立的地址空间)
};
//考虑到不同的进程有各自独立的地址空间,传递指针到另一个进程几乎没有任何意义。因此 sigqueue 函数很少传递指 针( sival_ptr ),大多是传递整型( sival_int )。
1.传统的信号多用 signal/kill 这两个函数搭配
2.signal函数的表达力有限,控制不够精准;所以引入了sigqueue函数来完成实时信号的发送
3.sigqueue函数也可以发送空信号(信号0)来检查进程是否存在。
4.和 kill 函数不同的地方在于,它不能通过将pid指定为负值而向整个进程组发送信号。
[2] sigaction(安装信号)
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
1.参数: signum: 信号编号
1.struct sigaction { // 第二个参数
union {
void (*sa_handler)(int);//sa_flags里没有设置SA_SIGINFO标记的信号处理函数
//sa_flags里设置了SA_SIGINFO标志, 的信号处理函数
void handle(int, siginfo_t *info, void *ucontext);
// 收到的额外数据保存在siginfo_t->si_value中的si_int和si_ptr中
}
sigset_t sa_mask; // 阻塞信号集
int sa_flags; // 标志
void (*sa_restorer)(void); // 恢复处理程序
};
2.
siginfo_t { // handle信号处理函数的第二个参数
int si_signo; // 信号的值
int si_code; // 信号来源:SI_USER.SI_TKILL.SI_QUEUE..
pid_t si_pid; // 信号发送进程的进程 ID 。
uid_t si_uid; //信号发送进程的真实用户 ID 。
union sigval si_value; //sigqueue 函数发送信号时所带的伴随数据。
...
}
3.ucontext是 void* 类型的,其实它是一个 ucontext_t 类型的变量。
这个结构体提供了进程上下文的信息,用于描述进程执行信号处理函数之前进程所处的状态。通常情况下信号处理函数很少会用到这个变量
4. sa_flags的含义
1.SA_NOCLDSTOP
一旦父进程为SIGCHLD信号设置了这个标志位,那么子进程停止和子进程恢复这两件事情,就不会向父进程发送 SIGCHLD信号了但是子进程切换为SIGCONT时还是会给父进程发送SIGCHLD信号。
2.SA_NOCLDWAIT
如果父进程为SIGCHLD设置了SA_NOCLDWAIT 标志位,那么子进程退出时,就不会进入僵尸状态,而是直接自行 了断。 对于Linux而言,子进程转换切换为SIGSTOP.SIGCONT.SIGKILL时都会给父进程发送SIGCHLD信号。这点 和上面的 SA_NOCLDSTOP 略有不同。
3.SA_ONESHOT 和 SA_RESETHAND
这两个标志位的本质是一样的,表示信号处理函数是一次性的,信号递送出去之后,信号处理函数便恢复成默认值 SIG_DFL 。
4.SA_NODEFER 和 SA_NOMASK
这两个标志位的作用是一样的,在信号处理函数执行期间,不阻塞当前信号。
5.SA_RESTART
这个标志位表示,如果系统调用被信号中断,则不返回错误,而是自动重启系统调用
6.SA_SIGINFO
没有设置SA_SIGINFO:
跟signal使用方法相同, 使用一个参数的信号处理函数
void (*sa_handler)(int);
设置了SA_SIGINFO:
1.这个标志位表示信号发送者会提供伴随数据。这时使用带3个参数的信号处理函数
void handle(int, siginfo_t *info, void *ucontext);
2.能获取到发送进程的PID、UID.信号来源.及发送的额外信息...
2.注意
1.对SIGKILL 和 SIGSTOP,不可以为它们安装信号处理函数,也不能屏蔽掉这些信号。
若通过 sigaction 强行给 SIGKILL 或 SIGSTOP 注册信号处理函数,则会返回-1,并置errno为EINVAL。
[3].使用例子
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR printf("ERR: %d\n", __LINE__)
#define CUR printf("CUR: %d\n", __LINE__)
#define SIG_PHYSICAL SIGRTMIN+1 // 运动信号
enum physical {
BASKETBALL = 0x1, // 篮球
TENNIS = 0x2, // 网球
PINGPONG = 0x3, // 乒乓球
};
// 无SA_SIGINFO标志时,安装的信号处理函数
static void handle_(int signum)
{
printf("sig: sa_handler, no SA_SIGINFO\n");
}
// 有SA_SIGINFO标志时,安装的信号处理函数
static void _handle(int signum, siginfo_t *info, void *ucontext)
{ CUR;
switch(info->si_value.sival_int) {
case BASKETBALL:
printf("I will go basketball\n"); break;
case TENNIS:
printf("I will go tennis\n"); break;
case PINGPONG:
printf("I will go pingpong\n"); break;
default:
return; break;
}
printf("send pid = %d\n", info->si_pid);
printf("send si_uid = %d\n", info->si_uid);
printf("------------------------------\n");
}
void sig_eat(int signum)
{
printf("I will go eat\n");
}
int main(int argc, char **argv)
{
int ret, cldpid;
struct sigaction act;
sigset_t block_mask; // 阻塞信号集
union sigval sigval1, sigval2,sigval3;
sigval1.sival_int = BASKETBALL;
sigval2.sival_int = TENNIS;
sigval3.sival_int = PINGPONG;
printf("Usage:\n");
printf("%s [SA_SIGINFO]\n", argv[0]);
// 注册信号处理函数
if ((argc > 1) && (!strcmp(argv[1], "SA_SIGINFO"))){
memset(&act, 0, sizeof(act));
act.sa_sigaction = (void (*)(int, siginfo_t *, void *))_handle; // 有SA_SIGINFO标志时,安装的信号处理函数
act.sa_flags = SA_SIGINFO | SA_RESTART;
sigaction(SIG_PHYSICAL, &act, NULL); //安装一个可靠信号
}
else {
memset(&act, 0, sizeof(act));
act.sa_handler = handle_; // 无SA_SIGINFO标志时,安装的信号处理函数
act.sa_flags = 0;
sigaction(SIG_PHYSICAL, &act, NULL); //安装一个可靠信号
}
ret = fork();
if (ret < 0) {
ERR;
return -1;
}
else if(!ret) {
while(1){
sleep(2);
cldpid = getpid();
sigqueue(cldpid, SIG_PHYSICAL, sigval1);
sleep(1);
sigqueue(cldpid, SIG_PHYSICAL, sigval2);
sleep(1);
sigqueue(cldpid, SIG_PHYSICAL, sigval3);
sleep(3);
}
}
while(1)
pause();
return 0;
}
执行结果:
book@gui_hua_shu:/work/nfs_root/qt_fs_new/2system_pro/sig$ ./a.out
Usage:
./a.out [SA_SIGINFO]
sig: sa_handler, no SA_SIGINFO
sig: sa_handler, no SA_SIGINFO
sig: sa_handler, no SA_SIGINFO
^C
book@gui_hua_shu$ ./a.out SA_SIGINFO
Usage:
./a.out [SA_SIGINFO]
CUR: 36
I will go basketball
send pid = 11627
send si_uid = 1000
------------------------------
CUR: 36
I will go tennis
send pid = 11627
send si_uid = 1000
------------------------------
CUR: 36
I will go pingpong
send pid = 11627
send si_uid = 1000
------------------------------
^C
book@gui_hua_shu$