воскресенье, 17 июня 2012 г.

TID

В интернете свободно доступна интересная и полезная книга о программировании в Линуксе: Advanced Linux Programming. К несчастью, некоторые темы устарели. Одна из них - 4.5 GNU/Linux Thread Implementation. В книге говорится, что треды GNU/Linux реализованы как процессы. Следующий код должен это подтвердить, но он этого не делает:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void *thread_fun(void *arg)
{
    fprintf(stderr, "child thread pid is %d\n", (int)getpid());
    while(1);
    return NULL;
}

int main(void)
{
    pthread_t thread;
    fprintf(stderr, "main thread pid is %d\n", (int)getpid());
    pthread_create(&thread, NULL, &thread_fun, NULL);
    while(1);
    return 0;
}

Вместо разных PID программа показывает один:

$ ./alp-thread-pid
main thread pid is 17280
child thread pid is 17280

Как найти идентификатор треда? Есть простая функция pthread_t pthread_self(void);. Её нужно использовать при написании кросс-платформенной программы. Возвращаемый этой функцией идентификатор гарантированно уникален для процесса, но может быть повторно использован после завершения треда. Кроме того, тип возвращаемого значения непрозрачен - POSIX.1 разрешает использовать в качестве него арифметический тип или структуру. Поэтому даже распечатать такую величину невозможно, если неизвестно, как представляется идентификатор реализацией.
Однако ядро Линукс использует свои идентификаторы тредов. Их можно получить вызовом функции pid_t gettid(void);. Но glibc не предоставляет обертки к этому системному вызову! Хорошо, напишем свою и распечатаем результат:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

pid_t gettid(void)
{
    return syscall(SYS_gettid);
}

void *thread_fun(void *arg)
{
    fprintf(stderr, "child thread pid is %d\n", (int)getpid());
    fprintf(stderr, "child kernel thread tid is %d\n", (int)gettid());
    while(1);
    return NULL;
}

int main(void)
{
    pthread_t thread;
    fprintf(stderr, "main thread pid is %d\n", (int)getpid());
    fprintf(stderr, "main kernel thread tid is %d\n", (int)gettid());
    pthread_create(&thread, NULL, &thread_fun, NULL);
    while(1);
    return 0;
}

Запускаем:

$ ./thread-pid 
main thread pid is 18866
main kernel thread tid is 18866
child thread pid is 18866
child kernel thread tid is 18867

Получили TID, победа!

Комментариев нет: