sigqueue與kill詳解及實例

/***********************************************************************************************
相關函數:
     #include <sys/types.h>
     #include <signal.h>

     int kill(pid_t pid, int sig);

     int sigqueue(pid_t pid, int sig, const union sigval value);
***********************************************************************************************/

    kill 與 sigqueue兩個函數功能都是向進程發送信號
不同的是sigqueue函數可以傳遞用戶參數到信號處理函數中
如果要使用sigqueue函數,則必須將sigaction結構體中的flags設置爲SA_SIGINFO
同時將信號處理函數的地址賦值給sa_sigaction。

參數解釋:
    pid:    進程pid
    sig:    要發送的信號編碼
    sigval: 一個共用體, 可以傳遞一個整形參數,
            如果要傳遞多個參數時,可以將其包裝在一個結構體中然後賦給sival_ptr
            union sigval {
                int sival_int;
                void *sival_ptr;
            };
實例1:
    使用kill函數發送信號.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>


void sig_quit(int signo)
{
    if (SIGQUIT == signo) {
        printf("receive SIGQUIT\n");
    }
}

int main(void)
{

    sigset_t zeromask;
    sigemptyset(&zeromask);

    /****使用自定義信號捕捉函數捕捉SIGQUIT信號*****/
    if (mysignal(SIGQUIT, sig_quit) == SIG_ERR) {
        perror("mysignal error");
        return EXIT_FAILURE;
    }


    /**
     * sigsuspend函數的工作原理是:
     * 首先將之前設置爲阻塞的信號設置爲非阻塞,及捕捉那些信號
     * 然後調用pause函數掛起,直到直到接收到任意信號,並從此信號捕捉函數返回後才返回。
     **/
    sigsuspend(&zeromask);

    return EXIT_SUCCESS;
}
實例2:
    調用sigqueue函數發送信號。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>


struct value{
    pid_t pid;
    union sigval si_val;
};


void *thread_func(void *arg)
{
    sigqueue(((struct value*)arg)->pid, SIGUSR1,  ((struct value*)arg)->si_val);
    pthread_exit((void*)EXIT_SUCCESS);
}


void sig_usr(int signo, siginfo_t *info, void *context)
{
    if (SIGUSR1 == signo) {
        printf("receive SIGUSR1!\n");
        printf("info.si_int = %s\n", (char*)info->si_ptr);
    }
}

int main(void)
{
    char arg[] = "hello world!";
    struct value v;
    v.pid = getpid();  //得到進程id
    v.si_val.sival_ptr = (void*)arg;  //需要傳遞的參數

    sigset_t zeromask;
    sigemptyset(&zeromask);

    struct sigaction act;

    act.sa_sigaction = sig_usr;  //信號處理程序
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;   //設置sa_flags的標誌位SA_SIGINFO, 程序將自動調用sa_sigaction所指向的信號處理函數

    if (sigaction(SIGUSR1, &act, NULL) < 0) {
        perror("sigaction error");
        return EXIT_FAILURE;
    }

    int err;
    pthread_t tid;
    /****創建線程,在線程中向進程發送信號****/
    err = pthread_create(&tid, NULL, thread_func, (void*)&v);  
    if (err != 0) {
        perror("pthread_create error");
        return EXIT_FAILURE;
    }

    sigsuspend(&zeromask);

    /****等待線程退出***/
    pthread_join(tid);

    return EXIT_SUCCESS;
}
實例1中使用到的mysignal函數源碼:

#include <stdlib.h>
#include <signal.h>

typedef void sigfunc(int);

sigfunc *mysignal(int signum, sigfunc *func)
{
    struct sigaction act, oldact;

    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    if (SIGALRM == signum) {
#ifndef SA_INTERRUPT
        act.sa_flags = SA_INTERRUPT;
#endif
    } else {
        /***處SIGALRM信號外,都嘗試重啓系統調用***/
        act.sa_flags = SA_RESTART;
    }

    if (sigaction(signum, &act, &oldact) < 0) {
        return (SIG_ERR);
    }

    return (oldact.sa_handler);

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章