linux信号在多线程中的使用2

        本文会对信号的一些需要注意的地方进行详细的总结,下面所介绍的函数的定义可以在上一篇文章中查看linux信号在多线程中的使用1

sigaction

        在多线程环境中,主线程中创建的sigaction结构体会被每个子线程所继承。当你在主线程中调用sigaction函数来设置信号处理函数时,这些设置会应用于整个进程,包括主线程和所有未来创建的子线程。这是因为线程继承了父线程的信号处理设置。一旦新线程创建成功,它会从创建它的线程(父线程)那里继承信号处理设置,包括sigaction注册的信号处理函数。这意味着,如果你在主线程中使用sigaction注册了某个信号的处理函数,那么该信号的处理函数会被继承到所有由主线程创建的子线程中。

        示例1:

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

void getCurrentTime(char* curtime)
{
    time_t currentTime;
    struct tm* timeInfo;
    char timeString[80];

    // 获取当前时间
    currentTime = time(NULL);

    // 将时间转换为本地时间
    timeInfo = localtime(&currentTime);

    // 将时间格式化为字符串
    strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", timeInfo);
    strcpy(curtime,timeString);
}

void sig_handler(int signum) {
    char curtime[80];
    getCurrentTime(curtime);
    printf("Signal %d received in thread %lu,time:%s\n", signum, pthread_self(),curtime);
}

void* thread_function(void* arg) {
    // 线程函数中的代码...
    // 子线程继承了主线程的信号处理设置,包括信号处理函数。

    // 子线程可以进行其他操作...
    int t = sleep(5);
    printf("t:%d\n",t);

    return NULL;
}

int main() {
    // 在主线程中设置信号处理函数
    struct sigaction sa;
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);

    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, NULL);
    char curtime[80];
    getCurrentTime(curtime);
    printf("main thread time:%s\n",curtime);

    // 主线程可以进行其他操作...
    sleep(2);

    // 向子线程发送SIGUSR1信号
    pthread_kill(thread, SIGUSR1);

    pthread_join(thread, NULL);
    return 0;
}
输出结果:
main thread time:2023-08-03 07:32:59
Signal 10 received in thread 140202152482560,time:2023-08-03 07:33:01
t:2

        上述示例可以看出,当在主线程中通过sigaction设置SIGUSR1的信号处理函数后,创建子线程,子线程是可以继承主线程设置的信号处理函数的,并且在创建完子线程后,打印当前时间,sleep 2秒后发送SIGUSR1信号给子线程,此时子线程不会等待5秒,而是sleep了2s后立马去响应了信号处理函数。

          如果希望在子线程中设置不同的信号处理函数,你需要在每个子线程中独立地调用sigaction函数来进行设置

        示例2:

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

void getCurrentTime(char* curtime)
{
    time_t currentTime;
    struct tm* timeInfo;
    char timeString[80];

    // 获取当前时间
    currentTime = time(NULL);

    // 将时间转换为本地时间
    timeInfo = localtime(&currentTime);

    // 将时间格式化为字符串
    strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", timeInfo);
    strcpy(curtime,timeString);
}

void sig_handler(int signum) {
    char curtime[80];
    getCurrentTime(curtime);
    printf("Signal %d received in thread %lu,time:%s\n", signum, pthread_self(),curtime);
}

void sig_handler_thread(int signum) {
    char curtime[80];
    getCurrentTime(curtime);
    printf("thread:%lu Signal handle %d received,time:%s\n", pthread_self(),signum,curtime);
}


void* thread_function(void* arg) {
    struct sigaction sa;
    sa.sa_handler = sig_handler_thread;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);
    // 子线程可以进行其他操作...
    int t = sleep(5);
    printf("t:%d\n",t);

    return NULL;
}

int main() {
    // 在主线程中设置信号处理函数
    struct sigaction sa;
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);

    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, NULL);
    char curtime[80];
    getCurrentTime(curtime);
    printf("main thread time:%s\n",curtime);

    // 主线程可以进行其他操作...
    sleep(2);

    // 向子线程发送SIGUSR1信号
    pthread_kill(thread, SIGUSR1);

    pthread_join(thread, NULL);
    return 0;
}
输出:
main thread time:2023-08-03 08:11:28
thread:140644435814144 Signal handle 10 received,time:2023-08-03 08:11:30
t:2

        上面示例中,在主线程中设置了SIGUSR1的信号处理函数为sig_handler,又在子线程中重新设置SIGUSR1的信号处理函数为sig_handler_thread,在向子线程发送SIGUSR1信号后,子线程调用的是sig_handler_thread。

pthread_sigmask       

        如果想在子线程中屏蔽掉主线程设置的信号处理时,可以通过在子线程中调用pthread_sigmask对SIGUSR1信号设置BLOCK(屏蔽)。

        示例3:

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

void getCurrentTime(char* curtime)
{
    time_t currentTime;
    struct tm* timeInfo;
    char timeString[80];

    // 获取当前时间
    currentTime = time(NULL);

    // 将时间转换为本地时间
    timeInfo = localtime(&currentTime);

    // 将时间格式化为字符串
    strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", timeInfo);
    strcpy(curtime,timeString);
}


void sig_handler(int signum) {
    char curtime[80];
    getCurrentTime(curtime);
    printf("Signal %d received in thread %lu,time:%s\n", signum, pthread_self(),curtime);
}


void* thread_function(void* arg) {
    printf("thread:%ld is running!\n",pthread_self());
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    pthread_sigmask(SIG_BLOCK, &mask, NULL);
    int t= sleep(5);
    char curtime[80];
    getCurrentTime(curtime);
    printf("time:%s, t:%d ,thread:%ld exit!\n",curtime,t,pthread_self());
    return NULL;
}

int main() {
    // 在主线程中设置信号处理函数
    struct sigaction sa;
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);

    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, NULL);


    char curtime[80];
    getCurrentTime(curtime);
    printf("main thread time:%s\n",curtime);
    sleep(2);
    pthread_kill(thread,SIGUSR1);
    // 主线程等待子线程结束
    pthread_join(thread, NULL);

    return 0;
}
运行结果:
thread:140044021896960 is running!
main thread time:2023-08-03 07:59:03
time:2023-08-03 07:59:08, t:0 ,thread:140044021896960 exit!

        当创建完子线程后sleep 2秒后对子线程发送SIGUSR1信号,由于子线程屏蔽了对该信号的处理,所以不会触发信号处理函数,在子线程sleep 5秒后退出。

        如果设置了对信号的屏蔽字,那么子线程收到该信号号不会处理,但是如果在子线程中解除了对信号的屏蔽字,那么在解除前收到的信号,会在解除屏蔽后,触发调用信号处理函数进行处理。

        示例:

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

void getCurrentTime(char* curtime)
{
    time_t currentTime;
    struct tm* timeInfo;
    char timeString[80];

    // 获取当前时间
    currentTime = time(NULL);

    // 将时间转换为本地时间
    timeInfo = localtime(&currentTime);

    // 将时间格式化为字符串
    strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", timeInfo);
    strcpy(curtime,timeString);
}


void sig_handler(int signum) {
    char curtime[80];
    getCurrentTime(curtime);
    printf("Signal %d received in thread %lu,time:%s\n", signum, pthread_self(),curtime);
}


void* thread_function(void* arg) {
    printf("thread:%ld is running!\n",pthread_self());
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, SIGUSR1);
    pthread_sigmask(SIG_BLOCK, &mask, NULL);
    sleep(5);
    pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
    int t= sleep(2);
    char curtime[80];
    getCurrentTime(curtime);
    printf("time:%s, t:%d ,thread:%ld exit!\n",curtime,t,pthread_self());
    return NULL;
}

int main() {
    // 在主线程中设置信号处理函数
    struct sigaction sa;
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);

    pthread_t thread;
    pthread_create(&thread, NULL, thread_function, NULL);


    char curtime[80];
    getCurrentTime(curtime);
    printf("main thread time:%s\n",curtime);
    sleep(2);
    pthread_kill(thread,SIGUSR1);
    // 主线程等待子线程结束
    pthread_join(thread, NULL);

    return 0;
}
输出:
main thread time:2023-08-03 08:28:52
Signal 10 received in thread 139821752706816,time:2023-08-03 08:28:57
time:2023-08-03 08:28:59, t:0 ,thread:139821752706816 exit!

        上面这个例子在主线程中设置了SIGUSR1的信号执行函数,创建完子线程后等待2s向子线程发送SIGUSR1信号,由于在子线程中设置了SIGUSR1的信号屏蔽字,所以线程不会触发信号处理函数,在等待5s后,解除了对此信号的屏蔽,此时立刻触发了信号处理函数!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值