我认为pthread使用 clone 在linux中生成一个新的线程。但如果是这样,所有线程都应该有单独的 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;
}
然后,为什么?
答案 0 :(得分:4)
我不确定调用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
答案 1 :(得分:3)
errno
不是全局变量,而是扩展为int
类型左值的宏。在实践中,它会扩展到(*__errno_location())
或类似。getpid
是一个库函数,它返回POSIX过程中的进程 id,而不是伪造的Linux每个clone
pid。如今Linux具有最小的内核级功能,可以使线程具有近乎POSIX的兼容性,但是大多数仍然依赖于用户空间libc级别的丑陋黑客。