【问题标题】:How does POSIX Threads work in linux?POSIX 线程如何在 linux 中工作?
【发布时间】:2010-09-14 02:56:09
【问题描述】:

我认为 pthread 使用 clone 在 linux 中生成一个新的 thread。但如果是这样,所有线程都应该有各自的pid。否则,如果它们具有相同的 pid,则 libc 中的全局变量似乎是共享的。但是,当我运行以下程序时,我得到了相同的 pid,但 errno 的地址不同。

extern errno;
void*
f(void *arg)
{
    printf("%u,%p\n", getpid(), &errno);
    fflush(stdin);
    return NULL;
}

int
main(int argc, char **argv)
{
    pthread_t tid;
    pthread_create(&tid, NULL, f, NULL);
    printf("%u,%p\n", getpid(), &errno);
    fflush(stdin);
    pthread_join(tid, NULL);
    return 0;
}

那么,为什么?

【问题讨论】:

    标签: c linux pthreads


    【解决方案1】:

    我不确定调用 pthread_create() 时如何使用 clone()。也就是说,查看clone() man page,看起来有一个名为CLONE_THREAD 的标志:

    如果设置了 CLONE_THREAD,则孩子是 与 调用过程。做剩下的 更多关于 CLONE_THREAD 的讨论 可读,术语“线程”用于 指线程内的进程 组。

    线程组是在 Linux 2.4 支持 POSIX 线程 一组共享线程的概念 单个 PID。在内部,这共享 PID就是所谓的线程组 线程的标识符 (TGID) 团体。从 Linux 2.4 开始,调用 getpid(2) 返回 TGID 来电者。

    然后继续讨论gettid() 函数,用于获取进程中单个线程的唯一 ID。修改代码:

    #include <stdio.h>
    #include <pthread.h>
    #include <sys/types.h>
    #include <sys/syscall.h>
    #include <unistd.h>
    
    int errno;
    void*
    f(void *arg)
    {
        printf("%u,%p, %u\n", getpid(), &errno, syscall(SYS_gettid));
        fflush(stdin);
        return NULL;
    }
    
    int
    main(int argc, char **argv)
    {
        pthread_t tid;
        pthread_create(&tid, NULL, f, NULL);
        printf("%u,%p, %u\n", getpid(), &errno, syscall(SYS_gettid));
        fflush(stdin);
        pthread_join(tid, NULL);
        return 0;
    }
    

    (请务必使用“-lpthread”!)我们可以看到各个线程 id 确实是唯一的,而 pid 保持不变。

    rascher@coltrane:~$ ./a.out 
    4109,0x804a034, 4109
    4109,0x804a034, 4110
    

    【讨论】:

    • 非常感谢您的帮助!但是从 glibc externed 的 errno 呢?它也是独一无二的。(虽然常规的全局变量是共享的)
    • 这是正确的——内核空间“PID”是用户空间“TID”,内核空间“TGID”是用户空间“PID”。
    • @dutor: errno 不是一个简单的 extern 变量 - 它具有特殊处理以使其成为每个线程(它使用宏定义:#define errno (*__errno_location ())
    【解决方案2】:
    1. 全局变量:您的错误是errno 不是全局变量,而是扩展为int 类型的左值的宏。在实践中,它会扩展为 (*__errno_location()) 或类似名称。
    2. getpid 是一个库函数,它返回 POSIX 意义上的进程的 process id,而不是伪造的 Linux per-clone pid。如今,Linux 具有使线程接近 POSIX 合规性所需的最小内核级功能,但其中大部分仍然依赖于用户空间 libc 级别的丑陋黑客攻击。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 2015-07-09
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多