- 在python3.8中,threading模块新引入了一个方法
threading.Thread.native_id可以获取操作系统分配给线程的唯一id。 - 但是在这之前,在python中获取线程id比较费劲,需要调用c库来实现,关于在Linux平台下,网上很多文章已经给出了方法,即通过
python ctypes库,调用libc库,使用libc中的syscall函数调用第186号(64位机器)系统调用(定义在sys/syscall.h中)来获取线程id。当我在macOS平台采用类似方法获取线程id时,被告知warning: 'syscall' is deprecated: first deprecated in macOS 10.12 - syscall(2) is unsupported; please switch to a supported interface.macOS已经不支持syscall了。 - 于是好奇python3.8是如何在macOS平台上获取线程id的。因此去github下载了python3.8的源码,找到了其中获取线程id的实现,发现其调用了
pthread_threadid_np函数,函数签名如下:
int pthread_threadid_np(pthread_t _Nullable,__uint64_t* _Nullable);
python3.8 源码中具体实现是这样的:
unsigned long PyThread_get_thread_native_id(void)
{
if (!initialized)
PyThread_init_thread();
#ifdef __APPLE__
uint64_t native_id;
(void) pthread_threadid_np(NULL, &native_id);
#elif defined(__linux__)
pid_t native_id;
native_id = syscall(SYS_gettid);
#elif defined(__FreeBSD__)
int native_id;
native_id = pthread_getthreadid_np();
#elif defined(__OpenBSD__)
pid_t native_id;
native_id = getthrid();
#elif defined(_AIX)
tid_t native_id;
native_id = thread_self();
#elif defined(__NetBSD__)
lwpid_t native_id;
native_id = _lwp_self();
#endif
return (unsigned long) native_id;
}
进一步追踪到pthread_threadid_np函数位于pthread.h头文件中,也就是在libpthread.dylib动态链接库中(macOS平台的动态链接库以dylib结尾)。
- 于是乎,我们便可以在python中调用该函数,代码实现如下
import ctypes
import sys
def get_thread_id():
libpthread = ctypes.cdll.LoadLibrary('libpthread.dylib')
tid = ctypes.c_uint64() # -> uint_64 tid;
libpthread.pthread_threadid_np(None, ctypes.pointer(tid)) # ctypes.pointer(tid) -> &tid
return tid.value
经过测试,该函数可以正确返回线程id
- 最后,综合macOS和Linux上获取线程id的方式,实现一个在两个平台都可以使用的函数,方便平时代码调试,实现如下
import ctypes
import sys
def get_thread_id():
if 'darwin' in sys.platform:
libpthread = ctypes.cdll.LoadLibrary('libpthread.dylib')
tid = ctypes.c_uint64() # -> uint_64 tid;
libpthread.pthread_threadid_np(None, ctypes.pointer(tid)) # ctypes.pointer(tid) -> &tid
return tid.value
elif 'linux' in sys.platform:
SYS_gettid = 186
libc = ctypes.cdll.LoadLibrary('libc.so.6')
tid = libc.syscall(SYS_gettid)
return tid
else:
raise NotImplementedError()