线程 ID
摘自《Linux 环境编程:从应用到内核》
在 Linux 中,目前的线程实现是 Native POSIX Thread Library,简称 NPTL。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都有一个调度实体,也拥有自己的进程描述符。
对于进程,可以使用下面的系统调用,获取进程 ID
pid_t getpid(void);
如:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h> int main()
{
pid_t pid = getpid();
printf("pid = %d\n", pid);
while();
return ;
}
打印:
jingyg@jingyg:~/share/mytest/linux_userspace/$ gcc -g -Wall 0_1_hello_world.c -o hello_world
jingyg@jingyg:~/share/mytest/linux_userspace/$ ./hello_world
pid =
使用 ps 命令查看进程 ID,(加 -L 选项可以显示线程信息,LWP:线程 ID(调用 gettid()系统调用的返回值),NLWP:线程组内的线程个数)
jingyg@jingyg:~$ ps -efL
UID PID PPID LWP C NLWP STIME TTY TIME CMD
jingyg : pts/ :: ./hello_world
可以看到 PID 和 LWP 的值一样。
多线程的进程,又被称作线程组,线程组内的第一个线程,在用户态被称作主线程(main thread)。内核在创建第一个线程时,会将线程组 ID (即进程 ID) 的值设置为第一个线程的线程 ID。
虽然 Linux 提供了 gettid 系统调用来返回线程 ID,但是可惜的是 glibc 并没有将该系统调用封装并开放给程序员使用。如果确实需要获取线程 ID,可以采用如下方法:
#include <sys/syscall.h>
int TID = syscall(SYS_gettid);
如
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h> int main()
{
pid_t pid = getpid();
printf("pid = %d\n", pid); int tid = syscall(SYS_gettid);
printf("tid = %d\n", tid);
return ;
}
打印:
jingyg@jingyg:~/share/mytest/linux_userspace/$ ./hello_world
pid =
tid =
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很有可能被复用:
#include <stdio.h>
#include <pthread.h> void* thread_work(void* param)
{
printf("pthread_self : %p\n", (void*)pthread_self());
return NULL;
} int main()
{
pthread_t tid = ;
int ret = pthread_create(&tid, NULL, thread_work, NULL);
ret = pthread_join(tid, NULL); ret = pthread_create(&tid, NULL, thread_work, NULL);
ret = pthread_join(tid, NULL);
return ;
}
打印:(编译 pthread 相关接口时,需要加上 -lpthread 选项,如 gcc -g -Wall 0_1_hello_world.c -o hello_world -lpthread)
jingyg@jingyg:~/share/mytest/linux_userspace/$ ./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\n", tid);
sleep();
return NULL;
} int main()
{
pthread_t tid1 = ;
pthread_t tid2 = ;
pthread_t tid3 = ;
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 ;
}
ps 命令查看线程 ID:
jingyg@jingyg:~$ ps -efL | grep hello_world
jingyg : pts/ :: ./hello_world
jingyg : pts/ :: ./hello_world
jingyg : pts/ :: ./hello_world
jingyg : pts/ :: ./hello_world
查看 proc:
jingyg@jingyg:~$ ll /proc//task/
total
dr-xr-xr-x jingyg jingyg Jul : ./
dr-xr-xr-x jingyg jingyg Jul : ../
dr-xr-xr-x jingyg jingyg Jul : /
dr-xr-xr-x jingyg jingyg Jul : /
dr-xr-xr-x jingyg jingyg Jul : /
dr-xr-xr-x jingyg jingyg Jul : /
线程 ID的更多相关文章
- linux查看某个进程的线程id(spid)
鉴于linux下线程的广泛使用 我们怎么查看某个进程拥有的线程id了 现在很多服务的设计 主进程->子进程->线程(比如mysql,varnish) 主进程负责侦听网络上的连接 并把连接发 ...
- 得到某个进程所有线程ID和入口地址
#include <windows.h> #include <tlhelp32.h> #include "iostream" using namespace ...
- 线程、线程句柄、线程ID
什么是句柄:句柄是一种指向指针的指针.我们知道,所谓指针是一种内存地址.应用程序启动后,组成这个程序的各对象是住留在内存的.如果简单地理解,似乎我们只要获知这个内存的首地址,那么就可以随时用这个地址 ...
- Android 开发 知晓各种id信息 获取线程ID、activityID、内核ID
/** * Returns the identifier of this process's user. * 返回此进程的用户的标识符. */ Log.e(TAG, "Process.myU ...
- 7.线程id,优先级讲解
1.线程id可以通过Thread对象的getId()方法得到,在线程出了问题,为什么CPU占用这么高的时候,查的时候我们可以在堆栈信息中找到对应线程,然后干掉该线程就好! 2.而线程对象的getNam ...
- linux获取线程ID
pthread_self()获取当选线程的ID.这个ID与pthread_create的第一个参数返回的相同.但是与ps命令看到的不同,因此只能用于程序内部,用于对线程进行操作. #include & ...
- 利用进程ID获取主线程ID
利用进程ID获取主线程ID,仅适用于单线程.多线程应区分哪个是主线程,区分方法待验证 (1)好像可以用StartTime最早的,不过通过线程执行时间不一定可靠,要是在最开始就CreateThread了 ...
- 线程、线程ID获取
一.进程ID获取 1.1 当前进程的Id 方法1 通过进程名获取 下面的例子中,也包含了获取该进程下的线程的方法. System.Diagnostics.Process[] processes:bo ...
- java 获取当前进程id 线程id
java 获取当前进程id 线程id RuntimeMXBean (Java Platform SE 8 ) https://docs.oracle.com/javase/8/docs/api/j ...
随机推荐
- 关于VC工程编译不过去这件事
刚开始接触VC的时候,很大一部分时间是在对付编译链接错误,因为经验不足的原因,这些编译链接总让人很沮丧.比如: 1.fatal error LNK1104: 无法打开文件“LIBC.lib”错误 这个 ...
- Threading.local
在多线程环境下,每个线程都有自己的数据.一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程,而全局变量的修改必须加锁. Threading.local可以创建 ...
- 题解-POI2014 FAR-FarmCraft
Problem bzoj权限题,洛谷上可提交 洛谷上的奇葩翻译不要看,很多条件缺漏 题意简述:给定一棵树,每条边权为1,给定所有点点权,每条边仅能走两次,求以一定顺序遍历整棵树后,使所有点中的到达时间 ...
- 《转》return *this和 return this有什么区别?
别跟我说 return *this 表示返回当前对象,return this 表示返回当前对象的地址(指向当前对象的指针). 正确答案为:return *this 返回的是当前对象的克隆或者本身(若返 ...
- 【转】C++拷贝构造函数详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: ; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量. 下面看一个类对象拷贝 ...
- Win10 开启移动热点 WiFi 的简单方法
原文地址:https://blog.csdn.net/u012318074/article/details/77162475 Win 10 开启移动热点 WiFi 的方法很简单,并不需要像网上那样还要 ...
- <pre>标签的基本样式设置
断行 在html中,换行符无法在一般标签内作为布局控制显示,包括xml实体 和 均表现为white-space,仅用于断字[1]. 一般情形下,可使用<br>标签断行:但需要从原始xml文 ...
- oracle 多行变一行 wmsys.wm_concat
背景 还是那个问题,部分程序员喜欢用sql解决问题.发现了这个函数,当初真是大喜过望,现在是哭笑不得.10g支持这个函数,11好像不支持了,而且只有oracle支持,其实自己写个通用方法 ...
- Sq lServer触发器的使用
创建表: CREATE TABLE [dbo].[GeneralRule]( [ID] [int] NOT NULL, ) NULL, [DeleteFlag] [int] NOT NULL ) CR ...
- Java+selenium chrome 常见的问题WebDriverException: unknown error: call function result missing 'value'
运行chrome浏览器 报错:"main" org.openqa.selenium.WebDriverException: unknown error: call function ...