C++ 为什么和什么时候应该';我不能杀一根线吗?

C++ 为什么和什么时候应该';我不能杀一根线吗?,c++,multithreading,sockets,networking,C++,Multithreading,Sockets,Networking,我正在编写一个多线程套接字服务器,我需要确定 关于线程的文章说,我应该等待线程返回,而不是终止它。但是,在某些情况下,我想要踢/禁止的用户线程将无法正常返回(例如,我开始发送一大块数据,而send()此时会阻止线程),因此我只需要杀死它 为什么终止线程函数是危险的?它们什么时候会使整个应用程序崩溃?如果您以很难的方式终止线程,它可能会泄漏资源 当您将线程设计为支持取消时,可以避免它 不要使用阻塞调用或使用带有超时的阻塞调用。以较小的数据块或异步方式接收或发送数据。原因有很多,但这里有一个简单的原

我正在编写一个多线程套接字服务器,我需要确定

关于线程的文章说,我应该等待线程返回,而不是终止它。但是,在某些情况下,我想要踢/禁止的用户线程将无法正常返回(例如,我开始发送一大块数据,而send()此时会阻止线程),因此我只需要杀死它


为什么终止线程函数是危险的?它们什么时候会使整个应用程序崩溃?

如果您以很难的方式终止线程,它可能会泄漏资源

当您将线程设计为支持取消时,可以避免它


不要使用阻塞调用或使用带有超时的阻塞调用。以较小的数据块或异步方式接收或发送数据。

原因有很多,但这里有一个简单的原因:只有一个堆。如果一个线程在堆上分配了任何东西,并且您杀死了它,那么它分配的任何东西都会一直存在,直到进程结束。每个线程都有自己的堆栈,因此可能会被释放(取决于实现),但您可以通过不让它自己关闭来保证堆上的泄漏。

杀死线程可能会导致程序泄漏资源,因为线程没有机会在其自身关闭后进行清理。考虑关闭线程正在发送的套接字句柄。这将导致阻塞send()立即返回,并返回相应的错误代码。然后,线程可以清理并和平地消亡。

如果一个线程在I/O中被阻塞,你永远不需要杀死它,相反,你可以在非阻塞I/O、超时和从另一个线程关闭套接字之间进行选择。这两种方法中的任何一种都将解除线程的阻塞。

终止线程意味着在当前位置停止所有执行。特别是,它不会执行任何析构函数。这意味着套接字和文件不会被关闭,动态分配的内存不会被释放,互斥锁和信号量不会被释放,等等。杀死线程几乎肯定会导致资源泄漏和死锁

因此,你的问题是相反的。真正的问题应该是:

何时以及在什么条件下可以终止线程

因此,当您确信不会发生泄漏和死锁时,您可以杀死线程,而不是现在,也不是在修改另一个线程的代码时(因此,几乎不可能保证)


在您的特定情况下,解决方案是使用非阻塞套接字,并在调用
send()
recv()
之间检查一些线程/用户特定的标志。这可能会使代码复杂化,这可能是您一直拒绝这样做的原因,但这是正确的方法


此外,您会很快意识到每客户端线程的方法无法扩展,因此您将改变您的体系结构,并以任何方式重新编写大量的内容。

您真的不想这样做

如果你在一个线程持有一个关键部分的时候杀死了它,它将不会被释放,这可能会导致整个应用程序崩溃。某些C库调用(如堆内存分配)使用关键部分,如果在线程执行“new”时碰巧杀死了它,那么从程序中的任何其他地方调用new将导致该线程停止



如果没有真正极端的措施,您就无法安全地执行此操作。这些措施的限制性比简单地向线程发送终止线程的信号要大得多。

您可能想提及操作系统……哦,对不起,我忘了。Windows XP SP3永远不要杀掉一个线程,因为你会用软管连接你的应用程序。因为,这违反了第六条戒律。@Noah“你不应该杀掉……否则你就有可能永远
void
,你应该
goto hell
”但是如何在阻止(赢)套接字时超时?使用非阻止套接字。或者设置一个适合您需要的超时。请记住,您可以分小块发送。此外,如果您确实在套接字上使用阻止I/O,那么从另一个线程上下文关闭套接字将取消阻止的I/O(无论如何,在Windows上),这样被阻止的线程将重新获得控制权并可以正确终止自身。这听起来很好,也很简单,但是它不会导致程序崩溃吗?它会导致现在已关闭套接字的线程发送失败,这正是point@Glorian:如果您的代码没有检查
send()
的返回代码,那么您可能确实有不可预测的行为。但是,在调用
send()
的过程中关闭套接字不会使应用程序崩溃。光滑的解决方案没有想到这一点。杀死线程的唯一好时机是在关闭整个进程的过程中执行该操作。+1:在Windows中,我们最终都会使用IO完成端口。@John:不幸的是,I/O完成端口不适合心脏病患者。我不会向某人推荐它,除非他们对其他套接字服务器设计有相当多的经验。使用单个I/O绑定线程的设计可以非常好地扩展(尽管它不会提供C10K服务器),并且更容易掌握,特别是对学生来说。@Andre:同意。但我也知道,像“在Windows中,我们最终都会有IO完成端口”这样的评论是促使我在许多情况下发现新技术的原因之一。java 1.4获得java.nio.*的主要原因之一是摆脱了每个套接字一个阻塞线程的方法,从而可以更好地扩展。即使你没有使用Java,看看这个API是如何设计的也是很有启发性的。严格地说,你可以释放由另一个线程分配的内存,只要该内存仍然是引用的(即,它在一个线程共享的数据结构中)。不过,这并不能防止线程在分配和指针存储之间被中断。安德烈说得没错,但我指的当然是线程分配的任何东西,线程之间没有以任何方式共享。但严格地说,您是正确的,因为如果它“共享”指针,它可以被取消分配,但即使是