Reputation: 19233
In my destructor I want to destroy a thread cleanly.
My goal is to wait for a thread to finish executing and THEN destroy the thread.
The only thing I found about querying the state of a pthread is pthread_attr_setdetachstate but this only tells you if your thread is:
Both of those have nothing to do with whether the thread is still running or not.
How do you query a pthread to see if it is still running?
Upvotes: 61
Views: 134788
Reputation: 1
I believe I've come up with a solution that at least works for Linux. Whenever I create a thread I have it save it's LWP (Light Weight Process ID) and assign it a unique name, eg. int lwp = syscall(SYS_gettid); prctl(PR_SET_NAME, (long)"unique name", 0, 0, 0);
Then, to check if the thread exists later I open /proc/pid/task/lwp/comm and read it. If the file exists and it's contents match the unique name I assigned, the thread exists. Note that this does NOT pass a possibly defunct/reused TID to any library function, so no crashes.
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/file.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>
pthread_t subthread_tid;
int subthread_lwp;
#define UNIQUE_NAME "unique name"
bool thread_exists (pthread_t thread_id)
{
char path[100];
char thread_name[16];
FILE *fp;
bool thread_exists = false;
// If the /proc/<pid>/task/<lwp>/comm file exists and it's contents match the "unique name" the
// thread exists, and it's the original thread (TID has NOT been reused).
sprintf(path, "/proc/%d/task/%d/comm", getpid(), subthread_lwp);
fp = fopen(path, "r");
if( fp != NULL ) {
fgets(thread_name, 16, fp);
fclose(fp);
// Need to trim off the newline
thread_name[strlen(thread_name)-1] = '\0';
if( strcmp(UNIQUE_NAME, thread_name) == 0 ) {
thread_exists = true;
}
}
if( thread_exists ) {
printf("thread exists\n");
} else {
printf("thread does NOT exist\n");
}
return thread_exists;
}
void *subthread (void *unused)
{
subthread_lwp = syscall(SYS_gettid);
prctl(PR_SET_NAME, (long)UNIQUE_NAME, 0, 0, 0);
sleep(10000);
return NULL;
}
int main (int argc, char *argv[], char *envp[])
{
int error_number;
pthread_create(&subthread_tid, NULL, subthread, NULL);
printf("pthread_create()\n");
sleep(1);
thread_exists(subthread_tid);
pthread_cancel(subthread_tid);
printf("pthread_cancel()\n");
sleep(1);
thread_exists(subthread_tid);
error_number = pthread_join(subthread_tid, NULL);
if( error_number == 0 ) {
printf("pthread_join() successful\n");
} else {
printf("pthread_join() failed, %d\n", error_number);
}
thread_exists(subthread_tid);
exit(0);
}
Upvotes: 0
Reputation: 343
pthread_kill(tid, 0);
No signal is sent, but error checking is still performed so you can use that to check existence of tid.
CAUTION: This answer is incorrect. The standard specifically prohibits passing the ID of a thread whose lifetime has ended. That ID might now specify a different thread or, worse, it might refer to memory that has been freed, causing a crash.
Upvotes: 27
Reputation: 1282
Let me note on the "winning" answer, which has a huge hidden flaw, and in some contexts it can lead to crashes. Unless you use pthread_join, it will coming up again and again. Assume you are having a process and a shared library. Call the library lib.so.
Let me point out, that this is not a hipothetical problem, I had the same issue on our project.
Upvotes: 4
Reputation: 35
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
void* thread1 (void* arg);
void* thread2 (void* arg);
int main()
{
pthread_t thr_id;
pthread_create(&thr_id, NULL, thread1, NULL);
sleep(10);
}
void* thread1 (void* arg)
{
pthread_t thr_id = 0;
pthread_create(&thr_id, NULL, thread2, NULL);
sleep(5);
int ret = 0;
if( (ret = pthread_kill(thr_id, 0)) == 0)
{
printf("still running\n");
pthread_join(thr_id, NULL);
}
else
{
printf("RIP Thread = %d\n",ret);
}
}
void* thread2 (void* arg)
{
// sleep(5);
printf("I am done\n");
}
Upvotes: -2
Reputation: 1834
It sounds like you have two questions here:
Answer: This is directly supported by pthreads -- make your thread-to-be-stopped JOINABLE (when it is first started), and use pthread_join() to block your current thread until the thread-to-be-stopped is no longer running.
Answer: You can add a "thread_complete" flag to do the trick:
Scenario: Thread A wants to know if Thread B is still alive.
When Thread B is created, it is given a pointer to the "thread_complete" flag address. The "thread_complete" flag should be initialized to NOT_COMPLETED before the thread is created. Thread B's entry point function should immediately call pthread_cleanup_push() to push a "cleanup handler" which sets the "thread_complete" flag to COMPLETED.
See details about cleanup handlers here: pthread cleanup handlers
You'll want to include a corresponding pthread_cleanup_pop(1) call to ensure that the cleanup handler gets called no matter what (i.e. if the thread exits normally OR due to cancellation, etc.).
Then, Thread A can simply check the "thread_complete" flag to see if Thread B has exited yet.
NOTE: Your "thread_complete" flag should be declared "volatile" and should be an atomic type -- the GNU compilers provide the sig_atomic_t for this purpose. This allows the two threads consistent access the same data without the need for synchronization constructs (mutexes/semaphores).
Upvotes: 48
Reputation: 73041
I think all you really need is to call pthread_join(). That call won't return until the thread has exited.
If you only want to poll to see whether the thread is still running or not (and note that is usually not what you should be wanting to do!), you could have the thread set a volatile boolean to false just before it exits... then your main-thread could read the boolean and if it's still true, you know the thread is still running. (if it's false, on the other hand, you know the thread is at least almost gone; it may still be running cleanup code that occurs after it sets the boolean to false, though, so even in this case you should still call pthread_join before trying to free any resources the thread might have access to)
Upvotes: 11
Reputation: 23614
There is not fully portable solution, look if your platform supports pthread_tryjoin_np or pthread_timedjoin_np. So you just check if thread can be joined (of course created with PTHREAD_CREATE_JOINABLE).
Upvotes: 6