【Linux】线程和信号

相比于进程中的信号处理,在线程中更加复杂,线程中的信号处理有如下特点:

  1. 每个线程都有自己的信号屏蔽字,但是信号的处理是进程中所有线程共享的。这意味着单个线程可以阻止某个信号,但是当某个线程修改了一个信号的处理行为,那么所有线程都会共享这个改变。
  2. 进程中的信号是递送到单个线程的。如果一个信号和硬件故障相关,那么该信号一般会被发送到引起该事件的线程中去,而其他的信号会被发送到任意的线程中。
屏蔽字修改
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);

sigprocmask函数用来修改进程的信号屏蔽字,但是它只能用在进程中,要修改线程的信号屏蔽字应使用函数pthread_sigmask.
pthread_sigmask的接口和使用方式和sigprocmask相同,只不过失败时返回值不像sigprocmask那样放回-1并设置errno,而是返回错误编号。

发送信号

kill将信号发送给进程,而向线程发送信号则使用函数pthread_kill.
int pthread_kill(pthread_t thread, int signo);
可以传一个0值的signo来检查线程是否存在。如果信号的默认处理动作是终止该进程,那么把信号发送给某个线程仍会杀死整个进程。

闹钟

闹钟定时器是进程资源,所有线程共享相同的闹钟。所以,进程中的多个线程不可能互不干扰的使用闹钟定时器。

sigwait函数
#include <signal.h>
int sigwait(const sigset_t  *restrict set, int *restrict signop);
  • 功能:

    线程可以通过调用sigwait函数等待一个或多个信号的出现。

  • 参数:
    set为要等待的信号集,返回时,signop指向的整数表明接收到的信号值。

如果在调用该函数时,信号集set中的某个信号处于挂起状态,那么函数会无阻塞地返回。返回前,sigwait将从进程中移除处于挂起状态的信号。若系统支持排队信号,则只移除该信号,其他信号继续排队。
为避免错误行为发生,线程在调用sigwait之前,必须阻塞要等待的信号。sigwait函数会原子地取消信号集的阻塞状态,直到有新的信号被传递。再返回前,sigwait会恢复线程的信号屏蔽字。
使用sigwait的好处在于它可以简化信号处理,允许把异步产生的信号用同步的方式处理。为防止信号中断线程,可以把信号加到每个线程的信号屏蔽字中。然后可以安排专用线程处理信号。这些线程可以进行函数调用,不需要担心在信号处理程序中调用哪些函数是安全地,因为这些函数调用来自正常的线程上下文,而非会中断线程正常执行的传统信号处理程序。

下面是一个使用专用线程处理信号的例子,参考自《APUE》12.8节。

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

int quitflag;
sigset_t mask;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t waitloc  = PTHREAD_COND_INITIALIZER;

void *pth_fn(void *args)
{
    int signo;
    while(1){
        sigwait(&mask, &signo);
        switch(signo){
            case SIGINT:
                printf("\ninterrupt\n");
                break;

            case SIGQUIT:
                pthread_mutex_lock(&lock);
                quitflag = 1;
                pthread_mutex_unlock(&lock);
                pthread_cond_signal(&waitloc);
                return 0;

            default:
                printf("unexpected signal %d\n", signo);
                exit(0);
        }
    }
}

int main()
{
    sigset_t oldmask;
    pthread_t tid;

    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);
    sigprocmask(SIG_BLOCK, &mask, &oldmask);

    pthread_create(&tid, NULL, pth_fn, NULL);

    pthread_mutex_lock(&lock);
    while(quitflag == 0)
        pthread_cond_wait(&waitloc, &lock);
    pthread_mutex_unlock(&lock);

    quitflag = 0;
    sigprocmask(SIG_SETMASK, &oldmask, NULL);

    return 0;
}

运行示例

$ ./a.out
^C
interrupt
^C
interrupt
^\$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值