Back to home

线程id,进程id,傻傻分不清楚?

初次发表于2015/3/13

【场景】
在格式化输出日志时,'%(asctime)s %(levelname)s {%(process)d-%(thread)d %(module)s.%(funcName)s:%(lineno)d} %(message)s'
输出内容形如:
14-12-26 17:02:40 INFO {7530--1219168576 role.run:139} Manager-1 is running
进程号7530很用ps命令很容易匹配,线程号-1219168576却有点茫然
【测试】
class Worker(Thread):
def __init__(self):
super(Worker, self).__init__()
def run(self):
print 'thread %s is running' % self.ident
def start_thread():
worker = Worker()
worker.setDaemon(True)
worker.start()
def test():
print 'main process %s is running' % os.getpid()
start_thread()
if "__main__" == __name__:
test()
输出:
main process 14257 is running
thread -1222096016 is running
此时,用pstree查看:
pstree -p 14257
python(14257)───{python}(14258)
【问题1
这个14258-1222096016到底是什么关系,为什么会有不同的标识
答案(来自网络):
从内核的角度来看,Linux并没有线程这个概念,它把所有的线程都当作进程来实现。每个Linux线程都同时具有线程id和进程id,其中进程id就是内核所维护的进程号,而线程id则由Linux Threads分配和维护。
__pthread_initial_thread 的线程idPTHREAD_THREADS_MAX__pthread_manager_thread的是2*PTHREAD_THREADS_MAX+1,第一个用户线程的线程idPTHREAD_THREADS_MAX+2,此后第n个用户线程的线程id遵循以下公式:
tid=n*PTHREAD_THREADS_MAX+n+1
这种分配方式保证了进程中所有的线程(包括已经退出)都不会有相同的线程id,而线程id的类型pthread_t定义为无符号长整型(unsigned long int),也保证了有理由的运行时间内线程id不会重复。
也就是说14258-1222096016描述的是同一个东东,两者也不能直接转换。
【问题2
只知线程id,想知道其对应的进程id,或者反之,怎么办呢?
答案:
可以用gdb->info threads查看:
# gdb -p 14257
GNU gdb (Gentoo 7.3.1 p2) 7.3.1
。。。
(gdb) info threads
Id Target Id Frame
2 Thread 0xb7284b70 (LWP 14258) "python" 0xb7726424 in __kernel_vsyscall ()
* 1 Thread 0xb75756c0 (LWP 14257) "python" 0xb7726424 in __kernel_vsyscall ()
十六进制的0xb7284b70换成十进制,就是-1222096016,这样就把14258-1222096016映射起来了。
这个办法比较土了,有更好的办法欢迎交流。
【问题3
搞清楚它们之间的映射关系有啥用呢?
a. 格式化的日志就可以方便地知道是pstree中哪个进程输出的了。
b. 发生死锁了
(gdb) py-bt
#5 Frame 0x9acfb9c, for file /opt/nsfocus/python/lib/python2.7/threading.py, line 127, in acquire (self=<_RLock(_Verbose__verbose=False, _RLock__owner=-1222276240, _RLock__block=, _RLock__count=1) at remote 0xb74a7dcc>, blocking=1, me=-1219193152)
锁是被一个id-1222276240的线程获取的,按照上面的办法,就不难知道具体是谁了
c. 其它场合,欢迎补充