为什么以及何时不应该终止线程?
我正在编写一个多线程套接字服务器,我需要确定。
关于线程的文章说我应该等待线程返回,而不是杀死它。但在某些情况下,我想要踢/禁止的用户线程将无法正确返回(例如,我开始发送一大块数据,而 send() 此时会阻塞线程),所以我会只需要杀死它。
为什么终止线程函数是危险的以及它们何时会使整个应用程序崩溃?
I am writing a multithreaded socket server and I need to know for sure.
Articles about threads say that I should wait for the thread to return, instead of killing it. In some cases though, the user's thread i want to kick/ban, will not be able to return properly (for example, I started to send a big block of data and send() blocks the thread at the moment) so I'll need just to kill it.
Why killing thread functions are dangerous and when can they crash the whole application?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
杀死一个线程意味着停止所有执行。特别是,它不会执行任何析构函数。这意味着套接字和文件不会被关闭,动态分配的内存不会被释放,互斥体和信号量不会被释放等等。杀死线程几乎肯定会导致资源泄漏和死锁。
因此,你的问题有点反了。真正的问题应该是:
因此,当您确信不会发生泄漏和死锁时,您可以杀死该线程,而不是现在,也不是当其他线程的代码将被修改时(因此,几乎不可能保证)。
在您的具体情况下,解决方案是使用非阻塞套接字并在调用
send()
和recv()
之间检查一些线程/用户特定的标志。这可能会使您的代码变得复杂,这可能就是您一直拒绝这样做的原因,但这是正确的方法。此外,您很快就会意识到每个客户端线程的方法无法扩展,因此无论如何您都将更改您的架构并重写其中的大部分内容。
Killing a thread means stopping all execution exactly where it is a the moment. In particular, it will not execute any destructors. This means sockets and files won't be closed, dynamically-allocated memory will not be freed, mutexes and semaphores won't be released, etc. Killing a thread is almost guaranteed to cause resource leaks and deadlocks.
Thus, your question is kind of reversed. The real question should read:
So, you can kill the thread when you're convinced no leaks and deadlocks can occur, not now, and not when the other thread's code will be modified (thus, it is pretty much impossible to guarantee).
In your specific case, the solution is to use non-blocking sockets and check some thread/user-specific flag between calls to
send()
andrecv()
. This will likely complicate your code, which is probably why you've been resisting to do so, but it's the proper way to go about it.Moreover, you will quickly realize that a thread-per-client approach doesn't scale, so you'll change your architecture and re-write lots of it anyways.
终止线程可能会导致程序泄漏资源,因为线程没有机会自行清理。考虑关闭线程正在发送的套接字句柄。这将导致阻塞的 send() 立即返回并带有适当的错误代码。然后线程可以清理并平静地消亡。
Killing a thread can cause your program to leak resources because the thread did not get a chance to clean up after itself. Consider closing the socket handle the thread is sending on. This will cause the blocking send() to return immediately with an appropriate error code. The thread can then clean up and die peacefully.
如果你以强硬的方式杀死你的线程,它可能会泄漏资源。
当您设计线程以支持取消时,您可以避免它。
不要使用阻塞调用或使用带超时的阻塞调用。以较小的块或异步方式接收或发送数据。
If you kill your thread the hard way it can leak resources.
You can avoid it when you design your thread to support cancelation.
Do not use blocking calls or use blocking calls with a timeout. Receive or send data in smaller chunks or asynchronously.
你真的不想这样做。
如果您在线程持有关键部分时杀死该线程,则该线程将不会被释放,这可能会导致整个应用程序崩溃。某些 C 库调用(例如堆内存分配)使用临界区,如果您在执行“new”时碰巧终止了线程,那么从程序中的其他任何位置调用 new 将导致该线程停止。
如果没有真正极端的措施,你根本无法安全地做到这一点,这些措施比简单地向线程发出信号以终止其自身具有更多的限制性。
You really don't want to do this.
If you kill a thread while it holds a critical section it won't be released which will likely result in your whole application breaking. Certain C library calls like heap memory allocation use critical sections and if you happen to kill your thread while it's doing a "new" then calling new from anywhere else in your program will cause that thread to stop.
You simply can't do this safely without really extreme measures which are much more restrictive than simply signalling the thread to terminate itsself.
原因有很多,但其中一个很简单:只有一个堆。如果一个线程在堆上分配了任何东西,并且你杀死了它,那么它分配的任何东西都会一直存在,直到进程结束。每个线程都有自己的堆栈,因此可以释放它(取决于实现),但是您可以通过不让它自行关闭来保证堆上的泄漏。
There's many reasons, but here's an easy one: there's only one heap. If a thread allocates ANYTHING on the heap, and you kill it, whatever it has allocated is around until the process ends. Each thread gets its own stack, and so that MAY be freed (implementation-dependent), but you GUARANTEE leaks on the heap by not letting it shut itself down.
如果线程在 I/O 中被阻塞,您永远不需要杀死它,而是可以在非阻塞 I/O、超时和从另一个线程关闭套接字之间进行选择。其中任何一个都会解除线程的阻塞。
In the case of a thread blocked in I/O you never really need to kill it, instead you have the choice between non-blocking I/O, timeouts, and closing the socket from another thread. Either of these will unblock the thread.