clinuxmultithreadingpthreadslinuxthreads

Does Posix thread ID have an one-to-one relation with linux thread ID?


I know the difference between pthread_self() and syscall(SYS_gettid). pthread_create() produces a POSIX thread ID which is represented by a struct pthread_t which is usually defined as an unsigned long int. We can use pthread_self to get the ID of the thread generated by pthread_create.

With strace, I know that pthread_create() in libpthread.so.0 is implemented by calling clone system call, which is also the system call used for fork(). After creating a POSIX thread by calling pthread_create(), a new POSXI thread (identified by thread ID returned by pthread_self()) and a new linux thread(identified by thread ID returned by syscall(SYS_gettid)) are produced. Does this mean POSIX thread ID have an one-to-one relation with linux thread ID? They just respectively represent the thread with pthread_t and pid_t?

Actually, sometimes I found that one linux thread ID maps to several POSIX thread IDs in the same process, which means that after producing a pair of POSIX thread ID and linux thread ID by calling pthread_create(), the POSIX thread ID changes while linux thread ID stays the same. Is there any way to change the POSIX thread ID while keeping the linux thread ID unchanged? If there is, which pthread function is it?

Thank you.

Here is the log by intercepting fork and pthread_create call. ltid means linux thread ID, tid means POSIX thread ID, pid means process ID.

1 message:  fork pid:12832  ltid:12832  tid:140300035462976     child pid:12848 ltid:12848  tid:140300035462976

2 message:  fork pid:12848  ltid:12848  tid:140549640255296     child pid:12849 ltid:12849  tid:140549640255296

3 message:  fork pid:12848  ltid:12848  tid:140549640255296     child pid:12850 ltid:12850  tid:140549640255296

4 message:  fork pid:12848  ltid:12848  tid:140549640255296     child pid:12851 ltid:12851  tid:140549640255296

5 message:  pthread_create pid:12848    ltid:12848  tid:139968995022656     child ltid:12865    tid:139968995018496 

6 message:  pthread_create pid:12848    ltid:12865  tid:139968995018496     child ltid:12865    tid:139968933345024

7 message:  fork pid:12832  ltid:12832  tid:140300035462976     child pid:12885 ltid:12885  tid:140300035462976

8 message:  fork pid:12885  ltid:12885  tid:139870512949056     child pid:12886 ltid:12886  tid:139870512949056

My explanation:

  1. (pid=12832, ltid=12832, tid=140...976) calls fork producing (pid=12848, ltid=12848, tid=140...976)
  2. (pid=12848, ltid=12848, tid=140...296) calls fork producing (pid=12849, ltid=12849, tid=140...296)
  3. (pid=12848, ltid=12848, tid=139...656) calls pthread_create producing (ltid=12865, tid=139...496)

The caller of 2 is the result of 1 according to linux thread ID(12848), but they have different POSIX thread IDs. The same goes for 1 and 5.

Here is the interception code fragment.

void *intermedia(void * arg){

    struct thread_param *temp;

    void *(*start_routine) (void *);
    temp=(struct thread_param *)arg;

    char test[1024]="";
    sprintf(test,"child ltid:%ld\ttid:%lu\n",syscall(SYS_gettid),pthread_self());
    log_message(test)

    return temp->start_routine(temp->args);    
}


int  pthread_create(pthread_t  *thread,  const pthread_attr_t  *attr,  void  *(*start_routine)(void  *),  void  *arg){
    static void *handle = NULL;
    static P_CREATE old_create=NULL;
    if( !handle )
    {
        handle = dlopen("libpthread.so.0", RTLD_LAZY);
        old_create = (P_CREATE)dlsym(handle, "pthread_create");
    }
    pthread_t tmp=pthread_self();
    char test[1024]="";
    sprintf(test,"pthread_create pid:%d\tptid:%ld\ttid:%lu\n",getpid(),syscall(SYS_gettid),tmp);
    log_message(test);

    struct thread_param *temp=malloc(sizeof(struct thread_param));
    temp->args=arg;
    temp->start_routine=start_routine;

    int result=old_create(thread,attr,intermedia,(void *)temp);

    return result;
}

pid_t fork(void){
    static void *handle = NULL;
    static FORK old_fork=NULL;
    if( !handle )
    {
        handle = dlopen("libc.so.6", RTLD_LAZY);
        old_fork = (FORK)dlsym(handle, "fork");
    }

    char test[1024]="";
    sprintf(test,"fork pid:%d\tltid:%ld\ttid:%lu\t",getpid(),syscall(SYS_gettid),pthread_self());

    pid_t ppid=getpid();
    pthread_t ptid=pthread_self();
    pid_t result=old_fork();
    if(result==0){
        sprintf(test,"%s\tchild pid:%d\tltid:%ld\ttid:%lu\n",test,getpid(),syscall(SYS_gettid),pthread_self());
        log_message(test);
    }
    return result;
}

Solution

  • Does Posix thread ID have an one-to-one relation with linux thread ID

    Yes.

    But consider this an implementation detail. Other OSs might do this differently.


    which is usually defined as

    pthread_t is opaque. As well do not make any assumptions on how it is implemented.


    I found that one linux thread ID maps to several POSIX thread IDs

    Really? I doubt this. At least not if all POSIX thread Ids in question were valid, that is the related thread either had not been joined yet or, if running detached, the thread had not ended yet.