微信号:Reboot51

介绍:专注于互联网运维开发分享、交流,让更多的运维工程师更加专注于自动化,为国内公有云开发、监控、运维贡献自己的力量.这里聚集着国内一线互联网工程师,乐于分享与交流 .

Python:线程之定位与销毁

2019-02-19 16:20 Lin_R


背景


开工前我就觉得有什么不太对劲,感觉要背锅。这可不,上班第三天就捅锅了。我们有个了不起的后台程序,可以动态加载模块,并以线程方式运行,通过这种形式实现插件的功能。而模块更新时候,后台程序自身不会退出,只会将模块对应的线程关闭、更新代码再启动,6 得不行。


于是乎我就写了个模块准备大展身手,结果忘记写退出函数了,导致每次更新模块都新创建一个线程,除非重启那个程序,否则那些线程就一直苟活着。这可不行啊,得想个办法清理呀,要不然怕是要炸了。

那么怎么清理呢?我能想到的就是两步走:

  1. 找出需要清理的线程号 tid;

  2. 销毁它们;


找出线程 ID


和平时的故障排查相似,先通过 ps 命令看看目标进程的线程情况,因为已经是 setName 设置过线程名,所以正常来说应该是看到对应的线程的。 直接用下面代码来模拟这个线程:


Python 版本的多线程


#coding: utf8
import threading
import os
import time

def tt():
   info = threading.currentThread()
   while True:
       print 'pid: ', os.getpid()
       print info.name, info.ident
       time.sleep(3)

t1 = threading.Thread(target=tt)
t1.setName('OOOOOPPPPP')
t1.setDaemon(True)
t1.start()

t2 = threading.Thread(target=tt)
t2.setName('EEEEEEEEE')
t2.setDaemon(True)
t2.start()


t1.join()
t2.join()


输出

root@10-46-33-56:~# python t.py
pid:  5613
OOOOOPPPPP 139693508122368
pid:  5613
EEEEEEEEE 139693497632512
...


可以看到在 Python 里面输出的线程名就是我们设置的那样,然而 Ps 的结果却是令我怀疑人生:

root@10-46-33-56:~# ps -Tp 5613
 PID  SPID TTY          TIME CMD
5613  5613 pts/2    00:00:00 python
5613  5614 pts/2    00:00:00 python
5613  5615 pts/2    00:00:00 python


正常来说不该是这样呀,我有点迷了,难道我一直都是记错了?用别的语言版本的多线程来测试下:


C 版本的多线程


#include<stdio.h>
#include<sys/syscall.h>
#include<sys/prctl.h>
#include<pthread.h>

void *test(void *name)
{    
   pid_t pid, tid;
   pid = getpid();
   tid = syscall(__NR_gettid);
   char *tname = (char *)name;
   
   // 设置线程名字
   prctl(PR_SET_NAME, tname);
   
   while(1)
   {
       printf("pid: %d, thread_id: %u, t_name: %s\n", pid, tid, tname);
       sleep(3);
   }
}

int main()
{
   pthread_t t1, t2;
   void *ret;
   pthread_create(&t1, NULL, test,  (void *)"Love_test_1");
   pthread_create(&t2, NULL, test,  (void *)"Love_test_2");
   pthread_join(t1, &ret);
   pthread_join(t2, &ret);
}


输出:

root@10-46-33-56:~# gcc t.c -lpthread && ./a.out
pid: 5575, thread_id: 5577, t_name: Love_test_2
pid: 5575, thread_id: 5576, t_name: Love_test_1
pid: 5575, thread_id: 5577, t_name: Love_test_2
pid: 5575, thread_id: 5576, t_name: Love_test_1
...


用 PS 命令再次验证:

root@10-46-33-56:~# ps -Tp 5575
 PID  SPID TTY          TIME CMD
5575  5575 pts/2    00:00:00 a.out
5575  5576 pts/2    00:00:00 Love_test_1
5575  5577 pts/2    00:00:00 Love_test_2


这个才是正确嘛,线程名确实是可以通过 Ps 看出来的嘛!


不过为啥 Python 那个看不到呢?既然是通过 setName 设置线程名的,那就看看定义咯:

[threading.py]
class Thread(_Verbose):
   ...
   @property
   def name(self):