一、sigqueue函數
功能:新的發送訊號系統調用,主要是針對即時訊號提出的支援訊號帶有參數,與函數sigaction()配合使用。
原型:int sigqueue(pid_t pid, int sig, const union sigval value);
參數:
sigqueue的第一個參數是指定接收訊號的進程id,第二個參數確定即將發送的訊號,第三個參數是一個聯合資料結構union sigval,指定了訊號傳遞的參數,即通常所說的4位元組值。
傳回值:成功返回0,失敗返回-1
typedef union sigval
{
int sival_int;
void *sival_ptr;
}sigval_t;
sigqueue()比kill()傳遞了更多的附加資訊,但sigqueue()只能向一個進程發送訊號,而不能發送訊號給一個進程組。
寫兩個小程式測試一下:
首先是接收訊號:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
|
/************************************************************************* > File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<signal.h>#define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) void handler(int, siginfo_t *, void *); int main(int argc, char *argv[]) { struct sigaction act; act.sa_sigaction = handler; //sa_sigaction與sa_handler只能取其一 //sa_sigaction多用於即時訊號,可以儲存資訊 sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; // 設定標誌位後可以接收其他進程 // 發送的資料,儲存在siginfo_t結構體中
if (sigaction(SIGINT, &act, NULL) < 0) ERR_EXIT("sigaction error"); for (; ;) pause(); return 0; } void handler(int sig, siginfo_t *info, void *ctx) { printf("recv a sig=%d data=%d data=%d\n", sig, info->si_value.sival_int, info->si_int); } |
在前面的《訊號捕捉與sigaction函數》中說過,sa_sigaction與SA_SIGINFO要配合使用,如上所示,siginfo_t 結構體也可以參見這篇文章。
然後是訊號發送:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
|
/************************************************************************* > File Name: process_.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<signal.h>#define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage %s pid\n", argv[0]); exit(EXIT_FAILURE); } pid_t pid = atoi(argv[1]); //字串轉換為整數 union sigval val; val.sival_int = 100; sigqueue(pid, SIGINT, val); // 只可以發訊號給某個進程,而不能是進程組
return 0; } |
測試如下:
先運行recv程式:
simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigqueue_recv
再ps出recv進程的pid,然後運行send程式:
simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigqueue_send 3323
則recv進程會輸出一條recv語句,當然我們也可以ctrl+c 給自己發送訊號,如下所示,結果是一樣的。
recv a sig=2 data=100 data=100
^Crecv a sig=2 data=100 data=100
^Crecv a sig=2 data=100 data=100
......................................................
需要提醒一下的是siginfo_t 結構體的兩個參數(int si_int; /* POSIX.1b signal */void
*si_ptr; /* POSIX.1b signal */)的值也會與si_value 一致,取決於發送的是sival_int 還是 sival_ptr。
二、即時訊號與不可靠訊號的區別
下面通過程式來說明區別,主要就是即時訊號支援排隊不會丟失。
先是recv程式:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
|
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h>#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) void handler(int); int main(int argc, char *argv[]) { struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigset_t s; sigemptyset(&s); sigaddset(&s, SIGINT); sigaddset(&s, SIGRTMIN); sigprocmask(SIG_BLOCK, &s, NULL); if (sigaction(SIGINT, &act, NULL) < 0) ERR_EXIT("sigaction error"); if (sigaction(SIGRTMIN, &act, NULL) < 0) ERR_EXIT("sigaction error"); if (sigaction(SIGUSR1, &act, NULL) < 0) ERR_EXIT("sigaction error"); for (;;) pause(); return 0; } void handler(int sig) { if (sig == SIGINT || sig == SIGRTMIN) printf("recv a sig=%d\n", sig); else if (sig == SIGUSR1) { sigset_t s; sigemptyset(&s); sigaddset(&s, SIGINT); sigaddset(&s, SIGRTMIN); sigprocmask(SIG_UNBLOCK, &s, NULL); } } |
在主函數中將SIGINT和SIGRTMIN訊號加入訊號屏蔽字,只有當接收到SIGUSR1訊號時才對前面兩個訊號unblock。需要注意的是如《訊號的未決與阻塞》中說的一樣:如果在訊號處理函數中對某個訊號進行解除阻塞時,則只是將pending位清0,讓此訊號遞達一次(同個即時訊號產生多次進行排隊都會抵達),但不會將block位清0,即再次產生此訊號時還是會被阻塞,處於未決狀態。
接著是send程式:
C++ Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
|
/************************************************************************* > File Name: sigrtime_send.c > Author: Simba > Mail: dameng34@163.com > Created Time: Sat 23 Feb 2013 02:34:02 PM CST ************************************************************************/ #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<fcntl.h> #include<stdio.h> #include<stdlib.h> #include<errno.h> #include<string.h> #include<signal.h>#define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage %s pid\n", argv[0]); exit(EXIT_FAILURE); } pid_t pid = atoi(argv[1]); //字串轉換為整數 union sigval val; val.sival_int = 100; sigqueue(pid, SIGINT, val); // 不可靠訊號不會排隊,即會丟失 sigqueue(pid, SIGINT, val); sigqueue(pid, SIGINT, val); sigqueue(pid, SIGRTMIN, val); //即時訊號會排隊,即不會丟失 sigqueue(pid, SIGRTMIN, val); sigqueue(pid, SIGRTMIN, val); sleep(3); kill(pid, SIGUSR1); return 0; } |
先是運行recv程式:
simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigrtime_recv2
接著ps出recv進程的pid,運行send程式:
simba@ubuntu:~/Documents/code/linux_programming/APUE/signal$ ./sigrtime_send 4076
在send程式中連續各發送了SIGINT和SIGRTMIN訊號3次,接著睡眠3s後使用kill函數發送SIGUSR1訊號給recv進程,此時recv進程會輸出如下:
recv a sig=34
recv a sig=34
recv a sig=34
recv a sig=2
即即時訊號支援排隊,3個訊號都接收到了,而不可靠訊號不支援排隊,只保留一個訊號。
參考:《APUE》