【问题标题】:What to do about a global mutex locked from a thread that then is killed如何处理从线程锁定的全局互斥锁,然后被杀死
【发布时间】:2021-12-12 00:28:15
【问题描述】:

如标题所示。我需要的功能涉及在某些条件下终止正在运行的线程。不幸的是,如果所述线程已锁定某个全局互斥锁,则该互斥锁将永远保持锁定,因为我正在使用一个线程尝试获取互斥锁的设计,但它仅在另一个线程完成一些工作后才被释放,这允许另一个线程调用第一个线程以再次重新获取它。由于第一个线程被杀死,互斥锁永远不会解锁,第二个线程被卡住并且无法对其执行任何操作。

我会在线程被杀死后解锁互斥锁(即,从同一线程的新实例中),但显然这是不允许的,并且会导致未定义的行为,因为互斥锁必须从锁定它的同一线程。我能做些什么呢?谢谢。

【问题讨论】:

  • 我需要的功能是在某些条件下杀死一个正在运行的线程真的,真的糟糕的想法。您无法知道线程是否还持有您无法控制的锁。
  • 如何在线程中捕获kill信号并在处理程序中释放互斥锁?
  • 你不能像那样简单地解锁一个锁。那把锁保护了一些东西不被并发访问,你认为你可以在它发生的中间打断这样的东西,解锁锁,一切都会正常工作吗?因此,当被杀死的线程处于malloc() 调用的中间,并且堆被锁定时,您打算如何安全地杀死该线程?你不能。
  • ...或重新设计,以便您不需要终止/杀死任何线程,直到操作系统在进程终止时执行它。
  • 任何线程都不应该强迫任何其他线程做任何事情(例如,死亡)。线程应该相互合作。如果线程 A 需要线程 B 死掉,那么线程 A 应该要求线程 B 死掉,而线程 B 应该被设计成能够及时响应请求,并干净地终止自己。

标签: c multithreading


【解决方案1】:

我需要的功能是在某些条件下终止正在运行的线程。

线程是一个实现细节。除非有很多您无法控制的代码,否则不可能需要杀死线程以获得功能。如果你在这种情况下,解决方法是将你无法控制的线程隔离到它自己的进程中。您可以安全地终止进程。

否则,您无法安全地终止线程。但你不必这样做。你需要做的是阻止线程做你不希望它做的工作,让它做你想做的工作。

您尚未描述线程正在执行的工作或您正在使用的线程标准,因此很难为您提供最佳方法的建议。但一般有两种做法:

  1. 有一些共享状态来跟踪需要完成的工作。让可能需要停止工作的代码定期检查是否应该停止工作。

  2. 使用某种信号方法向正在执行可能需要中断的工作的线程发出信号,表明它正在执行的工作可能不再需要完成。这避免了定期检查的需要,但通常不会避免共享状态的需要。

作为最后的手段,只需实现自己的互斥锁,该互斥锁支持在线程死亡后解锁。这样,线程将只保存一个支持该功能的互斥体实例。在您的实现中,将有一个受内部互斥锁保护的内部布尔值,表明该互斥锁已被持有。这样,当线程终止时,您只需获取内部互斥体,清除内部布尔值,然后释放内部互斥体。

您的逻辑如下所示:

要锁定互斥锁:

  1. 获取内部互斥体。
  2. 当内部布尔值为真时,等待内部条件变量。
  3. 将内部布尔值设置为 true。
  4. 释放内部互斥体。

解锁互斥锁:

  1. 获取内部互斥体。
  2. 将内部布尔值设置为 false。
  3. 广播内部条件变量。
  4. 释放内部互斥体。

现在,在线程死亡后,您可以调用上面的“解锁互斥锁”操作。 (当然,首先要确保互斥锁保护的任何状态都是一致的。)

【讨论】:

  • 感谢您的回复,大卫。正如我在评论中提到的那样,线程实际上会杀死自己。所以我记错了那一点。否则,最好不要让例行线程杀死程序核心功能的一部分。也就是说,您必须回答一个不同的问题。问题是关于如何在线程被杀死后解锁互斥锁。
  • @swaggg 我的第一段解决了这个问题——它不能安全地完成。但是有一个非常的机会你可以重新架构,这样线程就不会持有互斥锁。例如,您可以只使用受互斥锁保护的布尔值而不是互斥锁吗?然后你可以获取互斥锁,更改布尔值,然后释放互斥锁。 (编写自己的互斥锁并不难,可以在线程死亡后安全解锁。)
  • 是的,它会导致未定义的行为。问题更确切地说是如何处理这样的互斥体以及何时释放它以及如何释放它。与杀死线程是否安全无关。
  • @swaggg 这是一个真正的概括。一方面,考虑如果线程在持有其他内部互斥体时被终止,而该互斥体不支持在持有线程时被终止的线程,会发生什么情况。
  • @swaggg 不,不是真的。无论您在线程中放入什么,实现都可以实现您放入的任何东西,例如内部互斥锁,其状态会因终止线程而损坏。除非“杀死”你的意思是完全关闭,否则这将是一个完全不同的问题。 (Windows 以此而闻名。)
【解决方案2】:

正如@meaning-matters 所建议的,这应该是可能的,至少在 Linux 上,通过拦截实时信号 32 并使用 pthread_cancel,这是使用信号实现的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多