如何停止线程池中的线程

2019-10-31 15:08:36 +08:00
 rizon

本来以为是个很简单的事,用起来才发现完全不是那么回事。。。

场景是这样的,我用线程池去运行一个任务,希望在任务超时后就可以停止掉。 可是我发现 get 的超时不会让线程停下来,cancle 也不会让线程停下来。。。

所以到底该怎么停止线程?释放出线程池?

7065 次点击
所在节点    程序员
11 条回复
defphilip
2019-10-31 15:16:31 +08:00
正确的做法,是不要去停止线程,线程正常消亡才是正常的逻辑
要做取消,可以在外部设置类似于 disable 一样的标志位,线程内函数判断这个标志
ClericPy
2019-10-31 16:13:07 +08:00
这个不管什么语言, 在 stackoverflow 上都有人很详细的分析了, 自己去看看吧, 基本是个费力不讨好的操作, 一般都是在线程内自己主动停下.

目前就我所知, 除非语言本身考虑到处理这种情况, 不烦很复杂的. 比如在用 python 协程的时候, 挺多情况超时捎带的 cancel 可以把没跑完的协程给终止, 不过有些协程粒度不细, 还是停不下来.
yyyyfan
2019-10-31 16:26:25 +08:00
while(continueProcessing){
...
}
一般是采用标志位去停止,话说一般超时是会有回调的吧
DsuineGP
2019-10-31 16:55:17 +08:00
如果是 java 的话,调用执行线程的中断(interrupt)方法,在执行线程的业务代码中可以响应中断,并处理一些释放资源的逻辑.
但也并不是所有的线程状态都能响应中断,并发库中有一些更容易使用更安全的类,推荐看一下.
rizon
2019-10-31 18:38:28 +08:00
@defphilip
@ClericPy
那再问一下,线程里面开线程。父线程退出后,子线程还会继续运行吗
ClericPy
2019-10-31 18:48:21 +08:00
对 py 来说, 取决于子线程是不是 daemon, talk is cheap

from threading import Thread
import time


def parent():
t = Thread(target=child)
t.daemon = True
t.start()
for i in range(5):
print('parent', i)
time.sleep(0.5)


def child():
for i in range(10):
print('child', i)
time.sleep(0.5)


t = Thread(target=parent)
t.run()


执行会发现父线程在子线程 daemon 是 True 的时候不等, False 或默认的时候等. (这是为了定义清晰, 实际主线程看做父线程也一个意思)

但是注意, 这里的不等是不阻塞的意思, 结尾如果加一个 time.sleep(5), 会发现子线程是没有停止退出的, 这里不等只是让程序进程退出而不等.
ddup
2019-10-31 20:39:32 +08:00
子线程不会因为父线程的退出而停止,可以参考下 .NET CancellationToken 机制的实践。
yidinghe
2019-10-31 20:42:45 +08:00
线程实际上是没有……等下楼主你用的什么语言?
qyvlik
2019-10-31 21:36:54 +08:00
所有语言的线程实现都是类似的,包装了一次系统的线程。如果想停止正在运行中的线程,有几种方式:
1. 代码中检查线程的状态,例如 Java 的 Thread.currentThread().isInterrupted()
2. 语言本身支持 cpu 直接中断线程,然后把线程干掉,不过会有资源泄露的问题,毕竟不是正常退出。
3. 脚本语言的实现支持线程中断,例如你可以自己实现一个脚本引擎,在做指令派发的时候,将 指令 与 线程状态做位运算,线程状态是 0 的话,得到的指令是 0,0 可以定义为中止执行,就达到线程中断的要求。可以看看具体的代码: https://github.com/qyvlik/tinyvm/blob/40bfefac61d9e0409572b5b0c97f700f6f1532c8/tinyvm.cpp#L83
4. 进程被杀,线程一般也会退出,所以杀进程吧。
zhuangzhuang1988
2019-10-31 23:57:47 +08:00
@ddup 正解,微软的东西一直做得很完善的
还有进度报告
simuhunluo
2019-11-01 07:29:27 +08:00
父进程被杀,子进程还在,并且他的父进程 ID 置为 1。可以设置子进程为守护进程,这样父进程杀了之后子进程也没了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/614868

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX