Home > Mobile >  pthread_kill() funktion terminates my program
pthread_kill() funktion terminates my program

Time:12-04

pthread_kill() funktion terminates my program every time I launch it after a creation of a thread and try to send a SIGALRM signal. By the way, it works if I add a sleep() function before pthread_kill(). Then I add sleep() function in thread, because it terminates earlier then sending a signal.

void* funkcja_watku(){
    struct sigaction new_action = {.sa_handler = obsluga};
    sigaction(SIGALRM, &new_action, NULL);
    sleep(2);
    return 0;
}

int main(int argc, const char * argv[]) {
    pthread_t watek_id;
    
    //tworze watek
    if(pthread_create(&watek_id, NULL, &funkcja_watku, NULL))
        printf("Watek nie zostal utworzony\n");
    
    sleep(1);
    
    //wysylam sygnal
    if(pthread_kill(watek_id, SIGALRM))
        printf("Sygnal nie zostal wyslany\n");
    
    //usuwam watek
    if(pthread_join(watek_id, NULL))
        printf("Watek nie zostal usuniety\n");
  
    return 0;
}

I added the sleep function, but I dont think that It is the good way

CodePudding user response:

If you are using the pthread_kill function to send a signal to a thread, you need to make sure that the thread has registered a signal handler for that signal using the sigaction function before calling pthread_kill. Otherwise, the signal will not be delivered to the thread and your program will terminate.

In your code, you are calling sigaction in the thread function to register a signal handler for SIGALRM, but you are calling pthread_kill in the main function before the thread has had a chance to register the signal handler. This is why your program is terminating.

One solution to this problem would be to move the call to pthread_kill to the thread function, after the call to sigaction. This way, the thread will register the signal handler before pthread_kill is called, and the signal will be delivered to the thread as expected.

Here is an example of how you could modify your code to fix this problem:

void* funkcja_watku(){
    struct sigaction new_action = {.sa_handler = obsluga};
    sigaction(SIGALRM, &new_action, NULL);

    // send the signal after the signal handler has been registered
    pthread_kill(pthread_self(), SIGALRM);

    return 0;
}

int main(int argc, const char * argv[]) {
    pthread_t watek_id;

    // create the thread
    if(pthread_create(&watek_id, NULL, &funkcja_watku, NULL))
        printf("Watek nie zostal utworzony\n");

    // wait for the thread to finish
    if(pthread_join(watek_id, NULL))
        printf("Watek nie zostal usuniety\n");

    return 0;
}

CodePudding user response:

It doesn't kill your program. It terminates your thread, so your program exit peacefuly, since the join unblocks.

And it doesn't kill your thread neither. Your thread works correctly.

But, as you may know or not, sleep is interrupted whenever your receive a signal.

man 3 sleep

DESCRIPTION sleep() causes the calling thread to sleep either until the number of real-time seconds specified in seconds have elapsed or until a sig‐ nal arrives which is not ignored.

That is what sleep does...

Just add a second sleep after this one, and you'll. Or add a printf after your sleep, and you'll at least see that your thread is still alive. Its job is just over.

void* funkcja_watku(){
    struct sigaction new_action = {.sa_handler = obsluga};
    sigaction(SIGALRM, &new_action, NULL);
    sleep(2);
    printf("sleep over, because 2 sec has elapsed, or a signal was received\n");
    sleep(2);
    printf("second sleep is over\n");
    return 0;
}

Since I guess those sleep were just an experiment, it is just an experiment problem :D

Edit - answer to your comment

So, again, there is no problem in your code. Just sleep is behaving as expected, that is not sleeping as much as requested if a signal is received.

If you want a sleep that sleep the amount of time wanted, you can implement it yourself, by sleeping in a loop, resuming the sleep if it was interrupted by a signal.

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>

void obsluga(){
    printf("got alarm\n");
}

void* funkcja_watku(){
    struct sigaction new_action = {.sa_handler = obsluga};
    sigaction(SIGALRM, &new_action, NULL);
    struct timeval tv0, tv;
    gettimeofday(&tv0, NULL);
    for(;;){
        usleep(10000);
        gettimeofday(&tv, NULL);
        float delay=tv.tv_sec-tv0.tv_sec   1.0e-6*(tv.tv_usec-tv0.tv_usec);
        printf("\rsleeping... t=%5.2f / 2   ", delay);
        fflush(stdout);
        if(delay > 2.0) break;
    }
    return 0;
}

int main(int argc, const char * argv[]) {
    pthread_t watek_id;
    
    //tworze watek
    if(pthread_create(&watek_id, NULL, &funkcja_watku, NULL))
        printf("Watek nie zostal utworzony\n");
    
    sleep(1);
    
    //wysylam sygnal
    if(pthread_kill(watek_id, SIGALRM))
        printf("Sygnal nie zostal wyslany\n");
    
    //usuwam watek
    if(pthread_join(watek_id, NULL))
        printf("Watek nie zostal usuniety\n");
  
    return 0;
}

(In reality, here I do more than needed, because I wanted the cool display of seconds slept, to see the progress. But what I should have done is usleeping 2000000-(tv.tv_sec-tv0.tv_sec)*1000000 - (tv.tv_usec-tv0.tv_usec). That is usleeping the rest of wanted delay. So, if no signal occurs, there will be only one "normal" sleep, lasting 2 seconds. If one signal occurs, then there would be one interrupted sleep, then another, for the remaining of time. But, well, here I just sleep 10ms, and wait until 2 second have elapsed. So it doesn't matter if some of the 10 ms sleep are interrputed, we still exit the for loop only after 2 seconds.

You can change the delay to see for yourself that, indeed, the only cause of your problem was the fact that sleep is interrupted

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>

void obsluga(){
    printf("got alarm\n");
}

void* funkcja_watku(){
    struct sigaction new_action = {.sa_handler = obsluga};
    sigaction(SIGALRM, &new_action, NULL);
    struct timeval tv0, tv;
    gettimeofday(&tv0, NULL);
    for(;;){
        // We sleep approx 10 seconds by steps of 1 second
        sleep(1);
        gettimeofday(&tv, NULL);
        float delay=tv.tv_sec-tv0.tv_sec   1.0e-6*(tv.tv_usec-tv0.tv_usec);
        printf("sleeping... t=%5.2f / 10\n", delay); // No \r this time: I want to keep track of timings
        if(delay > 10.0) break;
    }
    return 0;
}

int main(int argc, const char * argv[]) {
    pthread_t watek_id;
    
    //tworze watek
    if(pthread_create(&watek_id, NULL, &funkcja_watku, NULL))
        printf("Watek nie zostal utworzony\n");
    
    // Important part is here to have not a multiple of 1 second. 
    // So that you'll see that, indeed, signal occurs in the middle 
    // of a sleep
    usleep(3500000);
    
    //wysylam sygnal
    if(pthread_kill(watek_id, SIGALRM))
        printf("Sygnal nie zostal wyslany\n");
    
    //usuwam watek
    if(pthread_join(watek_id, NULL))
        printf("Watek nie zostal usuniety\n");
  
    return 0;
}

Output is

sleeping... t= 1.00 / 10
sleeping... t= 2.00 / 10
sleeping... t= 3.01 / 10
got alarm
sleeping... t= 3.50 / 10
sleeping... t= 4.51 / 10
sleeping... t= 5.51 / 10
sleeping... t= 6.51 / 10
sleeping... t= 7.51 / 10
sleeping... t= 8.51 / 10
sleeping... t= 9.52 / 10
sleeping... t=10.52 / 10

Not only you see that you, as expected, got your signal after 3.5 seconds; that your thread still continues to run after the alarm is got. That, accordingly, the main thread still continues to pthread_wait until the thread has finished, which occurs only after 10 seconds. So everything is as you expected. But you also see that the 4th sleep is, as I told you, interrupted. It was supposed to last 1 second (between t=3 and t=4). But because the signal was received, it was interrupted, and ended at t=3.5 after half a second.

Subsequent sleeps are all uninterrupted (and because of that all end/start at times x.5 seconds)

  • Related