当一项常规工作完成后取消POSIX线程

5
有多个线程在执行任务,当一个线程成功时,所有的线程都应该被取消,因为工作已经完成。一旦一个线程成功终止,如何取消其他线程?谁会调用pthread_cancel(),成功的线程如何告诉main或生成它的线程(返回值?)。 更新 我不想简单地调用exit,因为我现在需要一些控制。例如,在线程被取消后,我将处理成功线程找到的结果,并可能进行一些额外的处理,或者只是想让进程继续运行一段时间以完成一些更多的工作。

如果你要丢弃除了一个线程之外的所有线程所做的工作,那么为什么需要多个线程来完成这个任务呢?只需在单个线程中执行一次即可完成工作。 - zwol
2
假设我有一个巨大的列表需要线性搜索,我会将列表分段传递给不同的线程,一旦其中一个找到匹配项,就返回结果。其他线程将被取消。 - phoxis
我猜在只有暴力搜索是唯一选择的情况下,这种做法是有道理的,但如果你的数据中有任何结构,那么就有更好的算法可用。 - zwol
我的应用程序使用暴力破解来生成所有可能的有效密码,或者从字典中读取密码并与哈希值进行比对,因此我需要在一个线程成功后取消其他线程。 - phoxis
2个回答

4
你可以选择一个简单的方案,让主函数执行所有操作。
main 函数中启动所有线程,并对某个信号量进行 down 操作。当线程完成任务时,对该信号量进行 up 操作。当主函数解锁时,它可以 pthread_cancel 所有线程(然后使用 pthread_join 确保)。
这样,main 函数启动和停止所有线程,所以应该相当简单。

是的,我的设计是基于主函数的,这是一个好主意。信号可以做任何事情吗? - phoxis
@phoxis 为了确保,您可以使用 pthread_kill 向线程发送信号。但是在这种情况下,我觉得这会很混乱(我想不出一种从信号处理程序中轻松离开线程的方法)。但是不要只听我的话,我总是避免使用信号。 - cnicutar
在主线程生成子线程的情况下,我喜欢使用互斥锁的解决方案,并将使用它。当线程被递归或随机生成而没有共同的父线程时,我询问了信号的情况,那种情况下信号可能有效。还是有其他方法来处理这种随机生成的取消操作? - phoxis
@phoxis 当然有办法。要取消一个线程,你只需要知道它的 pthread_t id。如果你有一个全局(且线程安全的)数据结构来保存这些id,那就更好了 :-) - cnicutar
好的,那我需要将它们作为全局变量。太棒了,感谢您解决问题(互斥解决方案)。 - phoxis

1

一个简单的方法是调用exit(),它会终止进程以及所有线程。它可以从任何线程中调用。

另一种方法是让主线程生成并等待工作线程,一旦其中一个工作线程完成以下操作之一:

  • 优雅地告诉其他线程终止并等待它们完成,或
  • 突然pthread_cancel()它们。默认情况下,线程创建时使用PTHREAD_CANCEL_DEFERRED,这意味着它们不会终止,直到调用任何取消点函数之一,请参见Thread Cancellation以获取良好的描述。因此,如果您的线程正在执行某些长时间计算,则可能希望将其取消状态设置为PTHREAD_CANCEL_ASYNCHRONOUS以立即终止线程,请参见pthread_setcanceltype

是的,这是我在发布之前使用的一种方式,但现在我想要更多的控制。例如,在线程被取消后,我将通过成功的线程处理找到的结果,并可能进行更多的处理。 - phoxis
你可以使用信号,但为什么要麻烦呢?pthread_cancel()已经足够激进了。 - Maxim Egorushkin
请注意,当启用异步取消时,您不允许调用任何库函数,甚至不包括strlen等。唯一允许的库操作是禁用异步取消。 - R.. GitHub STOP HELPING ICE
有趣。能否发布一个详细信息的链接? - Maxim Egorushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接