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);
}