Linux线程中的信号

版权声明:转载请声明 https://blog.csdn.net/qq_40732350/article/details/82728487

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

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

1.屏蔽字修改函数:

int pthread_sigmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);

sigprocmask函数:

用来修改进程的信号屏蔽字,但是它只能用在进程中,要修改线程的信号屏蔽字应使用函数pthread_sigmask.


pthread_sigmask函数:

和使用方式和sigprocmask相同,只不过失败时返回值不像sigprocmask那样放回-1并设置errno,而是返回错误编号。

how参数:

  1. SIG_BLOCK ,把原来的信号屏蔽集与set的信号集,构成一个并集,变成一个新的信号屏蔽集
  2. SIG_SETMASK ,把原来的信号屏蔽集与set的信号集,构成一个交集,变成一个新的信号屏蔽集
  3. SIG_UNBLOCK ,把set的信号集变成一个新的信号屏蔽集

2.发送信号

kill将信号发送给进程,而向线程发送信号则使用函数pthread_kill.

int pthread_kill(pthread_t thread, int signo);

可以传一个0值的signo来检查线程是否存在。如果信号的默认处理动作是终止该进程,那么把信号发送给某个线程仍会杀死整个进程。

利用这个函数可以向一指定的线程发送信号

扫描二维码关注公众号,回复: 3323728 查看本文章

代码实例:

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

int quitflag;
sigset_t mask;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  //初始化互斥量
pthread_cond_t waitloc  = PTHREAD_COND_INITIALIZER;  //初始化自动变量

void *pth_fn1(void *args)
{
    int signo;
    sigwait(&mask, &signo);

    if ( SIGINT == signo )
	{
		printf("\n%s interrupt\n", __FUNCTION__);
	}else
	{
		printf("没有这个信号处理\n");
	}
}
int main()
{
    sigset_t oldmask;
    pthread_t tid1;
	
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);
    pthread_sigmask(SIG_BLOCK, &mask, &oldmask);   //设置屏蔽字

    pthread_create(&tid1, NULL, pth_fn1, NULL);

	pthread_kill(tid1, SIGINT);  //向线程1发送信号
	
	sleep(1);  //wait thread return
	
    pthread_sigmask(SIG_SETMASK, &oldmask, NULL);   //还原屏蔽字
	printf("ok \n");
    return 0;
}

运行结果:

# ./a.out 

pth_fn1 interrupt
ok

3.闹钟

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

4.sigwait函数

int sigwait(const sigset_t *restrict set, int *restrict signop);

功能:

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

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

优点:

一个等待信号的线程,可以处理多个信号   

缺点:

当有多个信号等待一个不是指向特定线程的信号时,进程会把它发送到任意一个等待信号的线程

由于上面的特性,当处理不是指向特定线程的信号时,一般会把所有的信号处理集中到一个线程,

既方便管理,也方便调试

实例代码:

大概意思是

  1. 检验信号的处理情况
  2. 检验当多个线程等待信号时的情况
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.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("\n%s interrupt\n", __FUNCTION__);
                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);
        }
    }
}

void *pth_fn1(void *args)
{
    int signo;
    while(1){
        sigwait(&mask, &signo);
        switch(signo){
            case SIGINT:
                printf("\n%s interrupt\n", __FUNCTION__);
                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;
    pthread_t tid1;
	
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGQUIT);
    pthread_sigmask(SIG_BLOCK, &mask, &oldmask);   //设置屏蔽字

    pthread_create(&tid, NULL, pth_fn, NULL);
    pthread_create(&tid1, NULL, pth_fn1, NULL);
	
    pthread_mutex_lock(&lock);
    while(quitflag == 0)
        pthread_cond_wait(&waitloc, &lock);  //等待自动变量
    pthread_mutex_unlock(&lock);
	
    quitflag = 0;
    pthread_sigmask(SIG_SETMASK, &oldmask, NULL);   //还原屏蔽字
	printf("ok \n");
    return 0;
}

运行结果:

# ./a.out  

^C
pth_fn interrupt
^C
pth_fn interrupt
^C
pth_fn interrupt
^\ok 

root@:/home/# 

猜你喜欢

转载自blog.csdn.net/qq_40732350/article/details/82728487