Многопоточная обработка сигналов в C на Linux

Общий вопрос: что не так с моим кодом, так что все генерируемые сигналы не перехватываются двумя потоками обработчика?

Неудачные подробности моего плохого вопроса: я должен написать некоторый код с основной функцией, 3 потока генератора для генерации сигналов типа sig1 и sig2 и два потока обработки сигналов. Я пытался решить эту проблему с помощью кода, показанного ниже, но я сталкиваюсь с некоторыми ошибками. Я пытался использовать sigaction с sigwaitinfo и sigwait для перехвата сигналов. Но оба метода работают неправильно. В прикрепленном коде handler1 использует sigaction и sigwaitinfo, handler2 использует sigwait. Но я пытался, чтобы оба обработчика использовали один из них, и мои результаты никогда не были такими, как я полагаю, они должны быть. Кажется, что некоторые сигналы никогда не улавливаются. Что не так с моим кодом, чтобы все сигналы не перехватывались? Вот пример вывода

Пример вывода

сигнал 1 получен

сигнал 2 получен

сигнал 1 получен

сигнал 2 получен

сигнал 2 получен

sigSent1 == 2, sigSent2 == 7, sigReceived1 == 2, sigReceived2 == 3

Желаемый результат будет

Возможный желаемый вывод

сигнал 1 получен

сигнал 2 получен

сигнал 1 получен

сигнал 2 получен

сигнал 2 получен

сигнал 1 получен

сигнал 2 получен

сигнал 1 получен

сигнал 2 получен

sigSent1 == 4, sigSent2 == 5, sigReceived1 == 4, sigReceived2 == 5

Извините, если этот вопрос задает много вопросов, но я действительно не знаю, почему не все сигналы улавливаются, они гуглили и проверяли это примерно 6 часов сегодня и 3 часа вчера, а также просматривали справочные страницы. ..Я могу упустить что-то очевидное ...

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

/*
   Pre-definitions of functions
 */
void generator();
void handler1();
void handler2();
void reporter();
/*
   Global Variables 
 */
int total_signal_count=0;
int sentSignal1=0;
int sentSignal2=0;
int receivedSignal1=0;
int receivedSignal2=0;
sem_t s_lock;
sem_t r_lock;
sigset_t set;
pthread_mutex_t lock;
pthread_t tid[5];
/*
   Main function
 */
int main(int argc, char ** argv)
{
    int i=0;
    int randomNum=0;
    int error;
    int pid;
    sigset_t mask_all,mask_one,prev_one;
    //Setting up signals 
    //Get Random time
    time_t now;
    time(&now);
    //semaphore is initialized to be global and val 1
    sem_init(&s_lock,0,1);
    sem_init(&r_lock,0,1);
    srand((unsigned) time(&now));
    //Blakc in main thread
    sigemptyset(&set);
    sigaddset(&set,SIGUSR1);
    sigaddset(&set,SIGUSR2);
    pthread_sigmask(SIG_BLOCK,&set,NULL);
    pthread_sigmask(SIG_BLOCK,&set,NULL);
    //Loops until more threads created than 2
    while(i<3)
    {   error=pthread_create(&tid[i],NULL,(void*)generator,NULL);
        if(error!=0)
        {
            printf("failed to create thread\n");
        }
        i++;
    }//end while loop
    while(i<5)
    {
        error=pthread_create(&tid[3],NULL,(void*)handler1,NULL);
        if(error!=0)
        {
            printf("failed to create thread\n");
        }
        error=pthread_create(&tid[4],NULL,(void*)handler2,NULL);
        if(error!=0)
        {
            printf("failed to create thread \n");
        }
        i++;
    }
    //join the threads so main won't return
    i=0;
    int returnVal;
    sleep(10);
    printf("\n sigSent1==%d,sigSent2==%d,sigReceived1==%d,sigReceived2==%d\n",sentSignal1,sentSignal2,receivedSignal1,receivedSignal2);
    while(i<5)//Loops until threads are joined
    {
        //  printf("gonna join %d\n",i);
        pthread_join(tid[i],NULL);
        /*if((returnVal=pthread_join(tid[i],(void**)&returnVal))!=0)
          {
          printf("Error joining thread: %s at %d\n", strerror(returnVal),i);
          }*/
        i++;
    }//end while
    return 0;
}//end of main function
/*
   Generator threads
 */
void generator()
{
    sleep(1);
    int i=3;
    int randomNum=0;
    int val=0;
    int total_signal_c=9997;
    while(total_signal_c<10000)
    {
        usleep(1);
        //Randomly select to generate SIGUSR1 or SIGUSR2
        //Use pthread_kill(tid,SIGUSR1/SIGUSR2) to send the signal to a thread
        //  printf("total_signal_count%d\n",total_signal_c);
        //Create either a sig1 signal or sig2 signal
        randomNum=rand()%2;
        switch(randomNum)
        {
            case 0:
                val=pthread_kill(tid[3],SIGUSR1);
                if(val!=0)
                {
                    printf("kill fail ==%d\n",val);
                }
                sem_wait(&s_lock);
                //semaphore
                //mutex
                sentSignal1++;
                sem_post(&s_lock);
                break;
            case 1:
                val=pthread_kill(tid[4],SIGUSR2);
                if(val!=0)
                {
                    printf("kill fail2\n");
                }
                sem_wait(&s_lock);
                sentSignal2++;
                sem_post(&s_lock);
                //
                //
                break;
        }

        i++;
        total_signal_c++;
        //delay for a random time, 0.01 to 0.1 second
    }
}
/*
   Handler 1 threads
 */
void  handler1()
{
    //Setting up signals
    //  printf("In handler1\n");
    struct sigaction s;
    siginfo_t info;
    sigemptyset(&s.sa_mask);
    //use signal to perma block for handler2
    signal(SIGUSR2,handler1);
    //Add Sigusr1 to set
    sigaddset((&s.sa_mask),SIGUSR1);
    pthread_sigmask(SIG_BLOCK,&s.sa_mask,NULL);
    int val=-1;
    //use signal(), sigaddset(), pthread_sigmask() etc to block and unblock signals as required.
    while(1)
    {   //use sigwaitinfo(); to receive a signal
        val=-1;
        val=sigwaitinfo(&s.sa_mask,&info);
        //if signal received modify the corresponding counter
        if(info.si_signo==SIGUSR1){
            //increment semaphore lock
            sem_wait(&r_lock);
            receivedSignal1++;
            //decrement semaphore lock
            sem_post(&r_lock);
            printf("signal 1 received\n");
        }
        if(val==-1)     
        {
            //      break;
        }
    }
    pthread_exit(NULL);
}
/*
   Handler2 threads
 */
void handler2()
{
    int sigInfo=0;
    //use signal to perma block for handler2
    signal(SIGUSR1,handler2);
    int val=-1;
    while(1)
    {       //use sigwaitinfo(); to receive a signal
        val=-1;
        val=sigwait(&set,&sigInfo);
        //if signal received modify the corresponding counter
        if(sigInfo==SIGUSR2){
            //increment semaphore lock
            sem_wait(&r_lock);
            receivedSignal2++;
            //decrement semaphore lock
            sem_post(&r_lock);
            printf("signal 2 received\n");
        }       
    }
    pthread_exit(NULL);
}
4 голоса | спросил Inquirer107 1 22016vEurope/Moscow11bEurope/MoscowTue, 01 Nov 2016 07:04:46 +0300 2016, 07:04:46

1 ответ


0
  1. Из обработчика сигнала можно безопасно вызывать только асинхронно-безопасные функции. sigwait() и sigwaitinfo() не являются async-signal-safe. См. 2.4 Основные понятия сигнала на http: //pubs. opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html . Также см. Linux signal.7 справочная страница . printf() не является асинхронно-сигнальным безопасным.

  2. Вызов pthread_exit() в обработчике сигналов является неопределенным поведением. Это прервет поток - но в контексте обработки сигнала, потенциально вызывая значительные проблемы. Следующие вопросы только начинают касаться проблем, которые вызывают вызов pthread_exit() в обработчике сигналов: pthread_exit () в обработчике сигналов и Как правильно завершить поток в обработчике сигналов? См. также http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html

По сути, ваш код запутан. Вы запускаете handler1() и handler2() как отдельные темы затем зарегистрируйте те же функции, что и обработчики сигналов, и затем вызовите sigwait() /sigwaitinfo() внутри функций.

Учитывая то, как код комбинирует потоки, обработчики сигналов, циклы while(1)..., практически невозможно даже начать догадываться о том, что происходит. Например, вы можете получать потоки, которые порождают обработчики сигналов, которые застревают в бесконечных циклах.

Эта строка кода:

signal(SIGUSR1,handler2);

означает, что при получении SIGUSR1 handler2() будет вызываться в контексте сигнала, но handler2() имеет while(1) цикл в нем ...

Асинхронная обработка сигналов - сложная концепция для понимания. Я бы сказал, что вам нужно начать с чего-то гораздо более простого, чем несколько потоков, пытающихся сигнализировать друг другу.

ответил Andrew Henle 1 22016vEurope/Moscow11bEurope/MoscowTue, 01 Nov 2016 12:47:23 +0300 2016, 12:47:23

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132