【发布时间】:2015-06-08 15:34:30
【问题描述】:
在阅读了 Robert Love 的 this answer 和“Linux 内核开发”以及随后的 clone() 系统调用后,我发现 Linux 中的进程和线程(几乎)与内核无法区分。它们之间有一些调整(在引用的 SO 问题中讨论为“更多共享”或“更少共享”),但我仍有一些问题需要回答。
我最近在一个涉及几个 POSIX 线程的程序上工作,并决定在这个前提下进行试验。在创建两个线程的进程中,所有线程当然会获得由pthread_self() 返回的唯一值,然而,而不是getpid()。
我创建的示例程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
void* threadMethod(void* arg)
{
int intArg = (int) *((int*) arg);
int32_t pid = getpid();
uint64_t pti = pthread_self();
printf("[Thread %d] getpid() = %d\n", intArg, pid);
printf("[Thread %d] pthread_self() = %lu\n", intArg, pti);
}
int main()
{
pthread_t threads[2];
int thread1 = 1;
if ((pthread_create(&threads[0], NULL, threadMethod, (void*) &thread1))
!= 0)
{
fprintf(stderr, "pthread_create: error\n");
exit(EXIT_FAILURE);
}
int thread2 = 2;
if ((pthread_create(&threads[1], NULL, threadMethod, (void*) &thread2))
!= 0)
{
fprintf(stderr, "pthread_create: error\n");
exit(EXIT_FAILURE);
}
int32_t pid = getpid();
uint64_t pti = pthread_self();
printf("[Process] getpid() = %d\n", pid);
printf("[Process] pthread_self() = %lu\n", pti);
if ((pthread_join(threads[0], NULL)) != 0)
{
fprintf(stderr, "Could not join thread 1\n");
exit(EXIT_FAILURE);
}
if ((pthread_join(threads[1], NULL)) != 0)
{
fprintf(stderr, "Could not join thread 2\n");
exit(EXIT_FAILURE);
}
return 0;
}
(这是在 64 位 Fedora 上编译的 [gcc -pthread -o thread_test thread_test.c];由于 pthread_t 使用的 64 位类型源自 <bits/pthreadtypes.h>,因此代码需要稍作更改才能在 32 位版本上编译。 )
我得到的输出如下:
[bean@fedora ~]$ ./thread_test
[Process] getpid() = 28549
[Process] pthread_self() = 140050170017568
[Thread 2] getpid() = 28549
[Thread 2] pthread_self() = 140050161620736
[Thread 1] getpid() = 28549
[Thread 1] pthread_self() = 140050170013440
[bean@fedora ~]$
通过在gdb 中使用调度程序锁定,我可以保持程序及其线程处于活动状态,这样我就可以捕获top 所说的内容,仅显示进程:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28602 bean 20 0 15272 1112 820 R 0.4 0.0 0:00.63 top
2036 bean 20 0 108m 1868 1412 S 0.0 0.0 0:00.11 bash
28547 bean 20 0 231m 16m 7676 S 0.0 0.4 0:01.56 gdb
28549 bean 20 0 22688 340 248 t 0.0 0.0 0:00.26 thread_test
28561 bean 20 0 107m 1712 1356 S 0.0 0.0 0:00.07 bash
当显示线程时,说:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
28617 bean 20 0 15272 1116 820 R 47.2 0.0 0:00.08 top
2036 bean 20 0 108m 1868 1412 S 0.0 0.0 0:00.11 bash
28547 bean 20 0 231m 16m 7676 S 0.0 0.4 0:01.56 gdb
28549 bean 20 0 22688 340 248 t 0.0 0.0 0:00.26 thread_test
28552 bean 20 0 22688 340 248 t 0.0 0.0 0:00.00 thread_test
28553 bean 20 0 22688 340 248 t 0.0 0.0 0:00.00 thread_test
28561 bean 20 0 107m 1860 1432 S 0.0 0.0 0:00.08 bash
似乎很清楚,程序,或者可能是内核,与进程相比,有一种独特的方式来定义线程。根据top,每个线程都有自己的PID - 为什么?
【问题讨论】:
-
clone()正是 Linux 实现线程和fork()的方式。重要的是,与 PID 交谈会将信号传递给需要了解的每个人。如果内核为线程分配额外的 ID,那不关你的事,也不会影响你与进程的对话方式。 -
好的link 可以通过。
-
"Linux 中的进程和线程(几乎)与内核无法区分" 嗯,这不是真的。关于 Linux 内核是如何工作的,对于进程和线程来说,几乎没有什么可以说的。拥有 vm 的视图?只有进程。可以安排吗?只有线程。有文件描述符表吗?只有进程。有优先权吗?只有线程。以此类推。
标签: c linux multithreading