zoukankan      html  css  js  c++  java
  • 线程 ID

    摘自《Linux 环境编程:从应用到内核》

      在 Linux 中,目前的线程实现是 Native POSIX Thread Library,简称 NPTL。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都有一个调度实体,也拥有自己的进程描述符。

    对于进程,可以使用下面的系统调用,获取进程 ID

    pid_t getpid(void);

    如:

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <unistd.h>
     4 
     5 int main()
     6 {
     7     pid_t pid = getpid();
     8     printf("pid = %d
    ", pid);
     9     while(1);
    10     return 0;
    11 }

    打印:

    jingyg@jingyg:~/share/mytest/linux_userspace/0$ gcc -g -Wall 0_1_hello_world.c -o hello_world
    jingyg@jingyg:~/share/mytest/linux_userspace/0$ ./hello_world 
    pid = 3929

    使用 ps 命令查看进程 ID,(加 -L 选项可以显示线程信息,LWP:线程 ID(调用 gettid()系统调用的返回值),NLWP:线程组内的线程个数)

    jingyg@jingyg:~$ ps -efL
    UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
    jingyg    3929  3436  3929 99    1 03:07 pts/1    00:01:24 ./hello_world

    可以看到 PID 和 LWP 的值一样。
    多线程的进程,又被称作线程组,线程组内的第一个线程,在用户态被称作主线程(main thread)。内核在创建第一个线程时,会将线程组 ID (即进程 ID) 的值设置为第一个线程的线程 ID。

    虽然 Linux 提供了 gettid 系统调用来返回线程 ID,但是可惜的是 glibc 并没有将该系统调用封装并开放给程序员使用。如果确实需要获取线程 ID,可以采用如下方法:

    #include <sys/syscall.h>
    int TID = syscall(SYS_gettid);

     1 #include <stdio.h>
     2 #include <sys/types.h>
     3 #include <unistd.h>
     4 #include <sys/syscall.h>
     5 
     6 int main()
     7 {
     8     pid_t pid = getpid();
     9     printf("pid = %d
    ", pid);
    10 
    11     int tid = syscall(SYS_gettid);
    12     printf("tid = %d
    ", tid);
    13     return 0;
    14 }

    打印:

    jingyg@jingyg:~/share/mytest/linux_userspace/0$ ./hello_world 
    pid = 3995
    tid = 3995


    pthread_self()

    pthread 库中有一个 pthread_self() 接口用来获取线程 ID,但是这个 ID并不是内核中那个线程 ID

    #include <pthread.h>
    pthread_t pthread_self(void);

    pthread_t 到底是个什么样的数据结构呢?因为 POSIX 标准并没有限制 pthread_t 的数据类型,所以该类型取决于具体实现。对于 Linux 目前使用的 NPTL 实现而言,pthread_t 类型的线程 ID,本质上就是一个进程地址空间上的一个地址,而且 pthread_t 类型的线程 ID很有可能被复用:

     1 #include <stdio.h>
     2 #include <pthread.h>
     3 
     4 void* thread_work(void* param)
     5 {
     6     printf("pthread_self : %p
    ", (void*)pthread_self());
     7     return NULL;
     8 }
     9 
    10 int main()
    11 {
    12     pthread_t tid = 0;
    13     int ret = pthread_create(&tid, NULL, thread_work, NULL);
    14     ret = pthread_join(tid, NULL);
    15 
    16     ret = pthread_create(&tid, NULL, thread_work, NULL);
    17     ret = pthread_join(tid, NULL);
    18     return 0;
    19 }

    打印:(编译 pthread 相关接口时,需要加上 -lpthread 选项,如 gcc -g -Wall 0_1_hello_world.c -o hello_world -lpthread)

    jingyg@jingyg:~/share/mytest/linux_userspace/0$ ./hello_world 
    pthread_self : 0xb7525b40
    pthread_self : 0xb7525b40

    如果线程退出了,重新创建的线程很可能复用同一个 pthread_t 类型的 ID。在设计调试日志时,用 pthread_t 类型的 ID 来标识进程就不太合适了。

    采用 pid_t 类型的线程 ID 来唯一标识进程由以下优势:

    • 返回类型是 pid_t 类型,进程之间不会存在重复的线程 ID,而且不同线程之间也不会重复,在任意时刻都是全局唯一的值
    • proc 中记录了线程的相关信息,可以方便的查看 /proc/pid/task/tid 来获取线程对应的信息
    • ps 命令提供了查看线程信息的 -L 选项,可以通过输出中的 LWP 和 NLWP,来查看同一个线程组的线程个数和线程 ID 的信息

    如:

    #include <stdio.h>
    #include <pthread.h>
    #include <sys/syscall.h>
    
    void* thread_work(void* param)
    {
        int tid = syscall(SYS_gettid);
        printf("tid : %d
    ", tid);
        sleep(1000);
        return NULL;
    }
    
    int main()
    {
        pthread_t tid1 = 0;
        pthread_t tid2 = 0;
        pthread_t tid3 = 0;
        int ret = pthread_create(&tid1, NULL, thread_work, NULL);
        ret = pthread_create(&tid2, NULL, thread_work, NULL);
        ret = pthread_create(&tid3, NULL, thread_work, NULL);
    
        ret = pthread_join(tid1, NULL);
        ret = pthread_join(tid2, NULL);
        ret = pthread_join(tid3, NULL);
        return 0;
    }

    ps 命令查看线程 ID:

    jingyg@jingyg:~$ ps -efL | grep hello_world
    jingyg    4038  3436  4038  0    4 03:54 pts/1    00:00:00 ./hello_world
    jingyg    4038  3436  4039  0    4 03:54 pts/1    00:00:00 ./hello_world
    jingyg    4038  3436  4040  0    4 03:54 pts/1    00:00:00 ./hello_world
    jingyg    4038  3436  4041  0    4 03:54 pts/1    00:00:00 ./hello_world

    查看 proc:

    jingyg@jingyg:~$ ll /proc/4038/task/
    total 0
    dr-xr-xr-x 6 jingyg jingyg 0 Jul 20 03:54 ./
    dr-xr-xr-x 9 jingyg jingyg 0 Jul 20 03:54 ../
    dr-xr-xr-x 6 jingyg jingyg 0 Jul 20 03:54 4038/
    dr-xr-xr-x 6 jingyg jingyg 0 Jul 20 03:54 4039/
    dr-xr-xr-x 6 jingyg jingyg 0 Jul 20 03:54 4040/
    dr-xr-xr-x 6 jingyg jingyg 0 Jul 20 03:54 4041/
  • 相关阅读:
    USACO 3.3 A Game
    USACO 3.3 Camelot
    USACO 3.3 Shopping Offers
    USACO 3.3 TEXT Eulerian Tour中的Cows on Parade一点理解
    USACO 3.3 Riding the Fences
    USACO 3.2 Magic Squares
    USACO 3.2 Stringsobits
    USACO 3.2 Factorials
    USACO 3.2 Contact
    USACO 3.1 Humble Numbers
  • 原文地址:https://www.cnblogs.com/jingyg/p/5684377.html
Copyright © 2011-2022 走看看