信號(下)

上一節的說了使用kill函數來發送信號和使用signal函數來安裝信號處理函數,這一節我們使用另外一種方式來實現安裝信號處理和發送信號。

早期UNIX只支持SIGRTMIN之前的不可靠信號,後來增加了SIGRTMIN到SIGRTMAX的可靠信號,同時也增加了信號發送和安裝的方式,使用sigqueue()函數可以發送信號,使用sigaction函數可以添加信號。一般signal函數用於安裝不可靠信號,sigaction用於安裝可靠信號,但實際上兩個函數都可以安裝可靠信號和不可靠信號。

使用sigqueue函數代替kill函數發送信號:

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);

參數pid、sig和kill函數兩個參數一樣,分別為發送信號目標進程id和將要發送的信號,參數value是要隨信號一起發送給目標信號的數據,其類型為

union sigval {
   int sival_int;
   void *sival_ptr;
};

如果接收信號進程使用SA_SIGINFO標識安裝了sa_sigaction處理函數,那麼該值在siginfo_t的成員si_value中可以獲得。 使用函數sigaction可以安裝一個信號處理函數:

#include <signal.h>
int sigaction(int signum, const struct sigaction *act,  struct sigaction *oldact);

參數signum和signal函數第一個參數一樣,是將要安裝處理函數的的信號; 參數act是將要安裝的信號處理,其是一個結構體:

struct sigaction {
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t*, void*);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
};

第一,二個成員是信號處理函數,成員sa_handler類似signal函數的第二個參數,可以為信號處理函數或SIG_DFL或SIG_IGN。sa_sigaction有三個參數,第一個處理的信號,第二個參數為一個結構體siginfo_t類型的變量;第三個參數沒有使用。結構體siginfo_t為:

siginfo_t {
    int si_signo; /* Signal number */
    int si_errno; /* An errno value */
    int si_code; /* Signal code */
    int si_trapno; /* Trap number that causedhardware-generated signal(unused on most architectures) */
    pid_t si_pid; /* Sending process ID */
    uid_t si_uid; /* Real user ID of sending process */
    int si_status; /* Exit value or signal */
    clock_t si_utime; /* User time consumed */
    clock_t si_stime; /* System time consumed */
    sigval_t si_value; /* Signal value */
    int si_int; /* POSIX.1b signal */
    void* si_ptr; /* POSIX.1b signal */
    int si_overrun; /* Timer overrun count; POSIX.1b timers */
    int si_timerid; /* Timer ID; POSIX.1b timers */
    void* si_addr; /* Memory location which caused fault */
    long si_band; /* Band event (was int in glibc 2.3.2 and earlier) */
    int si_fd; /* File descriptor */
    short si_addr_lsb; /* Least significant bit of address since Linux 2.6.32) */
}

sigaction成員sa_mask指定在信號處理程序執行過程中,哪些信號應當被阻塞。缺省情況下當前信號本身被阻塞,防止信號的嵌套發送,除非指定SA_NODEFER或者SA_NOMASK標誌位。

sa_flags中包含了許多標誌位,包括剛剛提到的SA_NODEFER及SA_NOMASK標誌位。另一個比較重要的標誌位是SA_SIGINFO,當設定了該標誌位時,表示信號附帶的參數可以被傳遞到信號處理函數中,因此,應該為sigaction結構中的sa_sigaction指定處理函數,而不應該為sa_handler指定信號處理函數,否則,設置該標誌變得毫無意義。即使為sa_sigaction指定了信號處理函數,如果不設置SA_SIGINFO,信號處理函數同樣不能得到信號傳遞過來的數據,在信號處理函數中對這些信息的訪問都將導致段錯誤(Segmentation fault)。

sa_restorer已經不再使用。

void sig_func(int signo, siginfo_t* info, void* arg)
{
    // sleep(6);
    printf("====%s== [child] handle signo: %d==arg: %d=\n", __func__, signo,
           info->si_int);
}

void child_process_do(void)
{
    struct sigaction act;
    printf("====%s==child pid: %d===\n", __func__, getpid());
    //signal(SIGRTMIN, sig_func);
    //signal(SIGALRM, sig_func);
    act.sa_sigaction = sig_func;
    act.sa_flags = SA_SIGINFO;

    if (sigaction(SIGALRM, &act, NULL) < 0) { //此處安裝信號處理函數
        fprintf(stderr, "sigaction: %s\n", strerror(errno));
        return;
    }

    while (1) {
        sleep(10);
    }
}

void parent_process_do(pid_t pid)
{
    int i, val = 100;
    union sigval sigarg;
    sleep(1);
    printf("====%s==parent pid: %d===\n", __func__, getpid());

    for (i = 0; i < 5; i++) {
        printf("====%s==[parent] send signal <%d> to pid <%d>==\n", __func__, SIGRTMIN,
               pid);
        //kill(pid, SIGRTMIN);
        //kill(pid, SIGALRM);
        sigarg.sival_int = val + i;
        sigqueue(pid, SIGALRM,
                 sigarg); //此處發送SIGALRM信號,sigarg為要傳送的參數
        sleep(1);
    }

    waitpid(pid, NULL, 0);
}

int main(int argc, const char* argv[])
{
    pid_t pid;
    pid = fork();

    if (pid < 0) {
        fprintf(stderr, "fork: %s\n", strerror(errno));
        return -1;
    }

    if (0 == pid) {
        child_process_do();
    } else {
        parent_process_do(pid);
    }

    return 0;
}

不論何種安裝信號處理方式,都不能就不可靠信號改為可靠信號。使用信號的方式來進行進程間通信,需要知道對方進程的pid,並且信號通信的方式所能傳輸的信息量不是很多,在實際應用中信號可能更多的用在進程給自身發信號,用於進程間通信不多,所以使用信號來實現IPC不如前面幾節講的通信方式來得方便。

http://blog.csdn.net/shallnet/article/details/41451815 本節源碼下載


书籍推荐