信號,進程,線程

1 信號和進程

 Reference 

APUE P240

 #include <signal.h>
 typedef void (*sighandler_t)(int);
 sighandler_t signal(int signum, sighandler_t handler);

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
sigprocmask() is used to fetch and/or change the signal mask of the calling thread.The signal mask is the set of signals whose delivery is
currently blocked for the caller (see also signal(7) for more details).

 #include <signal.h>
 int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
The sigaction() system call is used to change the action taken by a process on receipt of a specific signal.  (See signal(7) for an overview of signals.)


Example:
void sig_segv(int sig, siginfo_t *info, void *puc)
{
    if (sig != SIGSEGV)
        error("signal");
    longjmp(jmp_env, 1);
}

void test_signal(void)
{
    struct sigaction act;
    struct itimerval it, oit;

    /* timer test */

    alarm_count = 0;

    act.sa_handler = sig_alarm;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    chk_error(sigaction(SIGALRM, &act, NULL));

    it.it_interval.tv_sec = 0;
    it.it_interval.tv_usec = 10 * 1000;
    it.it_value.tv_sec = 0;
    it.it_value.tv_usec = 10 * 1000;
    chk_error(setitimer(ITIMER_REAL, &it, NULL));
    chk_error(getitimer(ITIMER_REAL, &oit));
    if (oit.it_value.tv_sec != it.it_value.tv_sec ||
        oit.it_value.tv_usec != it.it_value.tv_usec)
        error("itimer");

    while (alarm_count < 5) {
        usleep(10 * 1000);
    }

    it.it_interval.tv_sec = 0;
    it.it_interval.tv_usec = 0;
    it.it_value.tv_sec = 0;
    it.it_value.tv_usec = 0;
    memset(&oit, 0xff, sizeof(oit));
    chk_error(setitimer(ITIMER_REAL, &it, &oit));
    if (oit.it_value.tv_sec != 0 ||
        oit.it_value.tv_usec != 10 * 1000)
        error("setitimer");

    /* SIGSEGV test */
    act.sa_sigaction = sig_segv;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    chk_error(sigaction(SIGSEGV, &act, NULL));

    if (setjmp(jmp_env) == 0) {
        *(uint8_t *)0 = 0;
    }

    act.sa_handler = SIG_DFL;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    chk_error(sigaction(SIGSEGV, &act, NULL));
}


2 信號和線程

A 線程會繼承父線程的信號屏蔽字
例子:該函數很好的說明了屬性A 的用法。效果是子線程屏蔽了所有信號,而主線程還是保留原來的屏蔽字。
void qemu_thread_create(QemuThread *thread,
                       void *(*start_routine)(void*),
                       void *arg, int mode)
{
    sigset_t set, oldset;
    int err;
    pthread_attr_t attr;

    err = pthread_attr_init(&attr);
    if (err) {
        error_exit(err, __func__);
    }
    if (mode == QEMU_THREAD_DETACHED) {
        err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        if (err) {
            error_exit(err, __func__);
        }
    }

    /* Leave signal handling to the iothread.  */
    sigfillset(&set);
    pthread_sigmask(SIG_SETMASK, &set, &oldset);
    err = pthread_create(&thread->thread, &attr, start_routine, arg);
    if (err)
        error_exit(err, __func__);

    pthread_sigmask(SIG_SETMASK, &oldset, NULL);

    pthread_attr_destroy(&attr);
}

B 每個線程可以有自己的信號屏蔽字,即線程可以調用pthread_sigmask 來設置自己的信號屏蔽字。
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
Compile and link with -pthread.
DESCRIPTION
       The  pthread_sigmask() function is just like sigprocmask(2), with the difference that its use in multithreaded programs is explicitly speci‐
       fied by POSIX.1-2001.  Other differences are noted in this page.

C 信號的處理是進程中所有線程共享的。 
    當線程修改了與某個信號相關的處理行爲後,所有的線程都必須共享這個處理行爲的改變。

D 進程中的信號是遞送到單個線程的。 如果信號是與硬件或者計時器超時有關,該信號就被髮送到引起該事件的線程中去,而其他的信號則被髮送到任意一個線程。
    (3要素)引起該事件的線程,  接受該事件的線程, 建立信號處理函數的線程
     信號處理函數是共享的,在哪個線程建立似乎不重要
     注意,如果一個線程屏蔽了只有它才能接受的信號,該信號將不會觸發信號處理函數

E  sigwait 
等待處於未決狀態的信號


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