Linux中pid与tid的异同及top中pid字段含义

简介


  • pid(process identifier),进程id。在整个操作系统中,每个进程的id唯一。
  • tid(thread identifier),线程id。在一个进程中,每个线程的id唯一,不同的进程可能有tid相同的线程。

这只是简单地描述,能够应付一般的应用场景,比如只是简单地区别进程和线程。

但是当使用htop/top查看所有线程时,PID一列显示的值会让你疑惑不解。因为它对线程依然显示的是pid。

因为对于pid和tid的真实含意,从用户视角(user view)和从内核视角(kernel view)看到的是不同的结果。

用户视角


在程序中获取这两个id并不难:

#include 
#include 
#include 
//#include 
//#include 

int main(void)
{
     
	using std::cout;
	using std::endl;
	
	cout << "getpid: " << getpid() << endl;
	cout << "gettid: " << pthread_self() << endl;
	cout << "gettid: " << std::this_thread::get_id() << endl; // same as the last line, c++11
	
	return 0;
}

输出如下:

getpid: 15439
gettid: 139708860868480
gettid: 139708860868480

对于用户来说,一般的应用就足够了。

除非,你有了一个需求,需要在一个进程中向另一个进程中的某个线程发送信号,接收信号的线程的id是哪个?

这就要说到内核视角了。

内核视角


对于操作系统内核来说,线程才是调度单元的最小单位。

因此,内核并没有严格区分进程和线程,而是把所有的线程都看作是进程,都有一个pid,只是把所有的线程进行了分组,同属一个组的线程可以共享内存,fd等。

可见,一个组里的进程就是用户视角的一个进程里的线程。

于是,这里没有tid的概念,只有pid。

那么,对于用户应用来说,如何获取到内核层面所谓的线程pid呢?

有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。

代码就一行:

#include 
#include 

cout << "gettid: " << syscall(SYS_gettid) << endl; // 这个值就对应了top中的pid列

理解了上面的内容,用户视角和内核视角的区别可以用下图示例:

Linux中pid与tid的异同及top中pid字段含义_第1张图片
看到了吧,用户视角看到的new thread的pid还是42的时候,内核已经把它作为44对待了。

小结


理解了pid、tid的异同之后,能够方便程序调试。

比如在编程时,启动线程的时候记录一下它的内核态pid,这样在top显示线程pid时就能对应上。

当线程出现问题,如内存使用过多,cpu使用率过高等时,能够快速定位到当事线程。

你可能感兴趣的:(Linux基础学习,pid,tid,异同)