linux系統編程之訊號(五):即時訊號與sigqueue函數

來源:互聯網
上載者:User

一、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》

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.