dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 8:26 am

hello,
I can't become clear about pthread_kill(pthread_t tid, int sig):

tid is clear, but which value of sig is required?
the man pages kill(1), (2), or (3) are absolutely ambiguous and confusing to me about that.

I just want to definitely kill a blocking thread (if that once coincidentally happens).
I can see when it blocks if a timestamp is not continuously incremented any more (actually sort of heartbeat).

(This is required for sort of an emergency brake action for a mobile robot)


dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 8:42 am

thank you,
but out of interest:
what stands 9 for?
Last edited by dsyleixa123 on Fri Jun 14, 2019 8:49 am, edited 2 times in total.

jahboater
Posts: 4587
Joined: Wed Feb 04, 2015 6:38 pm

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 8:49 am

dsyleixa123 wrote:
Fri Jun 14, 2019 8:42 am
thank you,
but out of interest:
what stands 9 for?
SIGKILL
Its the strongest signal.
There may be a more suitable signal to stop a thread.
SIGTERM is another one to try.
Last edited by jahboater on Fri Jun 14, 2019 8:51 am, edited 1 time in total.

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 8:50 am

thank you,
so:
if I command from a very high prio thread
pthread_kill(tid, 9)
will that definitely cause the other (stalling) thread tid to stop unconditionally, is that correct?

jahboater
Posts: 4587
Joined: Wed Feb 04, 2015 6:38 pm

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 8:55 am

dsyleixa123 wrote:
Fri Jun 14, 2019 8:50 am
thank you,
so:
if I command from a very high prio thread
pthread_kill(tid, 9)
will that definitely cause the other (stalling) thread tid to stop unconditionally, is that correct?
Should do.
To be honest I haven't tried it on a thread like that, but "kill -9 <pid>" is just standard stuff.
You should include <signal.h>
There is also SIGTERM or SIGQUIT,

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 8:59 am

I see, thank you.
tbh, I was confused because I read at stackoverflow that pthread_kill just sends a termination request to the other thread, not compellingly killing it from the timeslice in case the other thread is not able to receive anything anymore - but probably I'm wrong about that.
Last edited by dsyleixa123 on Fri Jun 14, 2019 9:00 am, edited 1 time in total.


dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 9:01 am

I don't know how to create an experimental setup which simulates such an event, tbh

jahboater
Posts: 4587
Joined: Wed Feb 04, 2015 6:38 pm

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 9:20 am

dsyleixa123 wrote:
Fri Jun 14, 2019 9:01 am
I don't know how to create an experimental setup which simulates such an event, tbh
How are you going to test it?

Perhaps just change the pthread_kill() call to be unconditional, or based on something external that you can control, like the presence of a file.

Use your imagination. The great thing about working on the Pi like this at home is that you cant easily break anything ...

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Fri Jun 14, 2019 9:22 am

yes I'll see what I can imagine

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Mon Jun 17, 2019 7:23 pm

I observed a problem: acc to pthread_kill man (3) this command (sending SIGKILL) appears to kill my entire program, not just the stallig thread -
is that true?
in case yes: what shall I do instead, by which command, to kill just the hung-up stalling thread (like stalling in loop_forever or while(1); ) ?

jahboater
Posts: 4587
Joined: Wed Feb 04, 2015 6:38 pm

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Mon Jun 17, 2019 9:40 pm

Yes, I had a bad feeling it would do that.
You probably should try a different signal (such as SIGTERM), catch it in the thread, and get the thread to terminate itself.

User avatar
Paeryn
Posts: 2604
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Tue Jun 18, 2019 12:01 am

jahboater wrote:
Mon Jun 17, 2019 9:40 pm
Yes, I had a bad feeling it would do that.
You probably should try a different signal (such as SIGTERM), catch it in the thread, and get the thread to terminate itself.
SIGTERM will terminate the process as a whole as well. You might be able to use

Code: Select all

pthread_cancel(thread_id);
That requests a thread to cancel, by default threads are in a deferred cancelability state which means a cancel request will be deferred until the next cancellation point (man pthreads for a list of functions that are cancellation points). You can set your thread to asynchronous with

Code: Select all

int old_cancel_state;  // This will be what the cancel state was before we changed it
if (pthread_setcancelstate(PTHREAD_CANCEL_ASYNCHRONOUS, &old_cancel_state)) {
  printf("Failed to set the cancel state.\n");
}
But be aware that cancelling a thread might leave resources locked, you can use pthread_cleanup_push() to register functions to call when cancelling. They will also be called if you exit your thread with pthread_exit() but not if your thread exits by returning from its function.

You still need to pthread_join() a cancelled thread, its exit status will be returned as PTHREAD_CANCELED.
She who travels light — forgot something.

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Tue Jun 18, 2019 7:17 am

thanks, but in my case the thread is stalling, i.e. it will never reach any a cancellation point - e.g. in this simple example -
- what exactly do you advice to add at which place?

Code: Select all



void* UART_thr(void*)          // UART comm (now just stalling)
{
   fprintf(stderr, "UART_thr: entered");
   while(1) ;  // mimics stalling forever
   
   fprintf(stderr, "UART_thr: leaving");  // <~~~~~~~~~~~~  will  never be reached
   return NULL;   
}



void* WATCHER_thr(void*)           // thread watcher  
{ 
   while(THREAD_ACTIVE)  {  //      
       //  cancel UART thread if no heart beat detected       
       if(!HEARTBEAT) {
           //  cancel UART thread  // <~~~~~~~~~ ????  pthread_kill ? pthread_cancel ?
       }   
   }
   return NULL;  //  
}


//

int main() {
       
    // threads    
    pthread_t       thread0, thread1, thread2;
    pthread_attr_t  thread_attr;
    struct sched_param   param;    

    // start multithreading      
    pthread_attr_init(&thread_attr);  // Initialise the attributes
    pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);  // Set attributes to RR policy

    param.sched_priority = 80;
    pthread_attr_setschedparam(&thread_attr, &param); // Set attributes to priority 80
    pthread_create(&thread0, &thread_attr, WATCHER_thr, NULL);     // low priority: keyboard monitor

    param.sched_priority = 40;
    pthread_attr_setschedparam(&thread_attr, &param); // Set attributes to priority 40 (policy is already RR)
    pthread_create(&thread1, &thread_attr, KBD_thr, NULL);     // low priority: keyboard monitor

    param.sched_priority = 40;
    pthread_attr_setschedparam(&thread_attr, &param); // Set attributes to priority 40 (policy is already RR)
    pthread_create(&thread2, &thread_attr, UART_thr, NULL);    // medium  priority: UART

    pthread_attr_destroy(&thread_attr); // We've done with the attributes     
    
    while(_TASKS_ACTIVE_) { delay(10); }
     
    // wait for threads to join before exiting
    pthread_join(thread0, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
   
    exit(0);
}

User avatar
Paeryn
Posts: 2604
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Tue Jun 18, 2019 1:22 pm

I've added some example code to what you gave which will allow the watcher thread to cancel the uart thread. I had to change the order of starting the threads as the watcher thread needs the id of the uart thread.

The pthread_cleanup_push() and pthread_cleanup_pop() functions are actually macros in gcc, they have to be matched and within the same lexical nesting level since pthread_cleanup_push() contains an opening curly bracket { and pthread_cleanup_pop() contains its matching closing curly bracket }. If the argument to pthread_cleanup_pop() is 0 then the corresponding cleanup function that was pushed won't be called, any other value will call it, this allows you to not bother calling calling it if you know you don't need to.

Code: Select all

[email protected]:~/Programming/asm/thread $ cat thread.c
#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>

volatile bool TASKS_ACTIVE = false;
volatile bool HEARTBEAT = false;

// This is the cleanup function for UART_thr, it will be called if the
// thread is cancelled or exits via pthread_exit(). Use it to release any
// resources the thread has.
void UART_thr_cleanup(void* data)
{
    printf("UART_thr cleanup.\n");
}

void* UART_thr(void* data)          // UART comm (now just stalling)
{
    int old;
    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old)) {
        printf("UART: Error setting async cancel state.\n");
        pthread_exit(NULL);
    }
    pthread_cleanup_push(UART_thr_cleanup, NULL);
    HEARTBEAT = true;
    for(int i = 0; i < 5; i++) {
        printf("UART: i = %d\n", i);
        sleep(1);
    }
    printf("UART: simulating stall\n");
    HEARTBEAT = false;
    while(1) ;  // mimics stalling forever
    pthread_cleanup_pop(true);
    return NULL;
}


// We pass in a pointer to the thread id which we may need to cancel
void* WATCHER_thr(void* heartbeat_id)           // thread watcher
{
    pthread_t heartbeat_thread_id = *(pthread_t*)heartbeat_id;
    bool THREAD_ACTIVE = true;
    printf("WATCHER: Checking heartbeat.\n");
    while(THREAD_ACTIVE)  {  //
        //  cancel UART thread if no heart beat detected
        if(!HEARTBEAT) {
            //  cancel UART thread  // <~~~~~~~~~ ????  pthread_kill ? pthread_cancel ?
            printf("WATCHER: Lost heartbeat, cancelling UART thread.\n");
            pthread_cancel(heartbeat_thread_id);
            THREAD_ACTIVE = false;
        }
    }
    TASKS_ACTIVE = false;
    return NULL;  //
}


//

int main() {

    // threads
    pthread_t       thread0, thread1, thread2;
    pthread_attr_t  thread_attr;
    struct sched_param   param;

    // start multithreading
    pthread_attr_init(&thread_attr);  // Initialise the attributes
    pthread_attr_setschedpolicy(&thread_attr, SCHED_RR);  // Set attributes to RR policy

    param.sched_priority = 40;
    pthread_attr_setschedparam(&thread_attr, &param); // Set attributes to priority 40 (policy is already RR)
    pthread_create(&thread2, &thread_attr, UART_thr, NULL);    // medium  priority: UART

    param.sched_priority = 80;
    pthread_attr_setschedparam(&thread_attr, &param); // Set attributes to priority 80
    pthread_create(&thread0, &thread_attr, WATCHER_thr, &thread2);     // high priority: heartbeat monitor

    pthread_attr_destroy(&thread_attr); // We've done with the attributes

    TASKS_ACTIVE = true;
    while(TASKS_ACTIVE) {
        printf("MAIN: tasks active, waiting\n");
        sleep(1);
    }
    printf("MAIN: threads ended, goodbye.\n");

    // wait for threads to join before exiting
    pthread_join(thread0, NULL);
    //pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    exit(0);
}

Code: Select all

[email protected]:~/Programming/asm/thread $ gcc thread.c -o thread -pthread
[email protected]:~/Programming/asm/thread $ ./thread
UART: i = 0
MAIN: tasks active, waiting
WATCHER: Checking heartbeat.
UART: i = 1
MAIN: tasks active, waiting
UART: i = 2
MAIN: tasks active, waiting
UART: i = 3
MAIN: tasks active, waiting
UART: i = 4
MAIN: tasks active, waiting
UART: simulating stall
Lost heartbeat, cancelling UART thread.
MAIN: tasks active, waiting
UART_thr cleanup.
MAIN: threads ended, goodbye.
[email protected]:~/Programming/asm/thread $
She who travels light — forgot something.

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Tue Jun 18, 2019 1:29 pm

wow, thank you very much Paeryn, that looks really awesome -
I am at my relatives just now but will run that immediately when I'm back!
Again, thanks a lot!

User avatar
Paeryn
Posts: 2604
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Tue Jun 18, 2019 2:38 pm

Just be careful with asynchronous cancels, there's no telling what the thread was doing when the cancel happens. Your cleanup functions should attempt to release any resources they have (file handles, allocated memory etc.) but if the thread got itself into a state where you aren't in control of it you need to be certain that any data you are cleaning up is valid.

For example: If your thread allocates memory then your cleanup function needs to be able to free it (because a cancel could happen before your thread frees it itself), if you do free it in the thread then you have to make sure that the cleanup function won't also try to free it.

Addendum:
If you are making any system calls you don't really want asynchronous cancels happening since a cancel could happen in the middle of such a call so try to limit setting asynchronous to only parts of the code that don't have any cancellation points for an extended time. My example code calls printf() whilst the thread is in asynchronous mode which is potentially bad if the cancel happens in the middle of it, but I know the code will only try cancelling after those have happened. You can manually insert cancellation points by calling pthread_testcancel() at key places, that will let you use the default deferred mode, but it will only help if you know that whatever loop your thread is stuck in is calling pthread_testcancel().

Code: Select all

// We can use the default deferred cancellation mode if we can make sure we
// always call pthread_testcancel() inside possible infinite loops without
// natural cancellation points.
void* UART_thr(void* data)          // UART comm (now just stalling)
{
    pthread_cleanup_push(UART_thr_cleanup, NULL);
    HEARTBEAT = true;
    for(int i = 0; i < 5; i++) {
        printf("UART: i = %d\n", i);
        sleep(1);
    }
    printf("UART: simulating stall\n");
    HEARTBEAT = false;
    while(1) {  // mimics stalling forever
        pthread_testcancel();
    }
    pthread_cleanup_pop(true);
    return NULL;
}
She who travels light — forgot something.

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Wed Jun 19, 2019 7:14 am

thanks again,
memory will probably not be allocated, just the file for UART (wiringPi: fd=serialOpen(*dev,clock) ); I will do serialClose(fd) then afterwards additionally.

I'll be back home soon and test then and report!
Last edited by dsyleixa123 on Wed Jun 19, 2019 3:40 pm, edited 1 time in total.

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Wed Jun 19, 2019 10:34 am

update:
Now I could test it, and it runs as expected!
thanks again, now I will work on restarting a cancelled thread anew and after that then on implementing the whole stuff to my UART communication program.
Thank you very much, I appreciate your help very much (code, hints, advices, and everything)!

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Wed Jun 19, 2019 10:59 pm

heya,
as to

Code: Select all

// We pass in a pointer to the thread id which we may need to cancel
void* WATCHER_thr(void* heartbeat_id)           // thread watcher
1 question about what I do not understand yet:
why do have to pass a different (special, arbitrary) thread pointer?
Finally the thread which is missing to send the heartbeat is the UART_thr (which has to be cancelled in case it fails), and it's ID is well-known: thread2!

So can't I simply cancel the thread2 by it's thread ID (which is a global constant by initialization, so probably not even has to be passed to thread0 via argument)?

Code: Select all

printf("WATCHER: Lost heartbeat, cancelling UART thread.\n");
pthread_cancel(thread2);

Code: Select all

pthread_create(&thread2, &thread_attr, UART_thr, NULL);    // medium  priority: UART
pthread_create(&thread0, &thread_attr, WATCHER_thr, NULL);  // high priority: thread watcher

User avatar
Paeryn
Posts: 2604
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Thu Jun 20, 2019 2:02 am

dsyleixa123 wrote:
Wed Jun 19, 2019 10:59 pm
heya,
as to

Code: Select all

// We pass in a pointer to the thread id which we may need to cancel
void* WATCHER_thr(void* heartbeat_id)           // thread watcher
1 question about what I do not understand yet:
why do have to pass a different (special, arbitrary) thread pointer?
Finally the thread which is missing to send the heartbeat is the UART_thr (which has to be cancelled in case it fails), and it's ID is well-known: thread2!

So can't I simply cancel the thread2 by it's thread ID (which is a global constant by initialization, so probably not even has to be passed to thread0 via argument)?

Code: Select all

printf("WATCHER: Lost heartbeat, cancelling UART thread.\n");
pthread_cancel(thread2);

Code: Select all

pthread_create(&thread2, &thread_attr, UART_thr, NULL);    // medium  priority: UART
pthread_create(&thread0, &thread_attr, WATCHER_thr, NULL);  // high priority: thread watcher
In the code you gave the three variables thread0, thread1 and thread2 aren't globals, they are all local to main() so the other functions wouldn't have access to them. You would need the UART thread to be started before the watcher thread anyway otherwise the watcher thread could theoretically try using the UART thread id before it gets set.

The reason it is passed as a void* and then cast back into what it should be is because the type signature of the function has to be that, the compiler would complain if you tried using a function that took a pthread_t as its parameter, and you can't cast thread2 itself to a void* (well you could but casting non-pointers into pointers and back is asking for trouble, not least that it assumes that a pointer is big enough to hold the other type).
She who travels light — forgot something.

dsyleixa123
Posts: 306
Joined: Mon Jun 11, 2018 11:22 am

Re: how to use pthread_kill(pthread_t tid, int sig) by which sig ?

Thu Jun 20, 2019 7:26 am

In the code you gave the three variables thread0, thread1 and thread2 aren't globals, they are all local to main() so the other functions wouldn't have access to them.
OMG, yes, stupid me...! Image

Return to “C/C++”