【问题标题】:Terminate loopless thread instantly without Abort or Suspend立即终止无循环线程而无需 Abort 或 Suspend
【发布时间】:2012-04-17 09:01:25
【问题描述】:

我正在实现一个协议库。这里是一个简化的描述。

主函数中的主线程将始终检查网络流(在 tcpclient 中)是否有一些数据可用。让我们说响应是接收到的消息,线程是一个正在运行的线程。

thread = new Thread(new ThreadStart(function));
thread.IsBackground = true;
thread.Start();

while(true){

response = receiveMessage();

if (response != null)
     {                
      thread.Suspend();
      //I am searching for an alternative for the line above and not thread.Abort().

      thread2 = new Thread(new ThreadStart(function2));
      thread2.IsBackground = true;
      thread2.Start();         
     }
}

到目前为止一切顺利,实际上有更多消息要进入 while 循环,并且还有一个状态机用于处理不同类型的传入消息,但这应该足够了。 (也不仅仅是函数“function”和“function2”)。

因此,无论如何,在这个应用程序中函数内部的外观并不清楚,因为协议对程序员是隐藏的,并且意味着是一个库。这意味着协议将根据程序在协议中的状态将一些程序员定义的函数作为线程启动。

因此,如果收到特殊响应(例如 callAnotherFunction 消息),我想终止 突然出现一个线程(此处称为“线程”),假设在 100 毫秒内。但我不知道它是否在循环内执行,以及在它终止之前需要多少处理。

如何在不弃用 Suspend 或 Exceptionthrowing Abort 功能的情况下停止这些线程? (请注意,我不能强制函数的程序员捕获 ThreadAbortException。)

或者我需要不同的程序架构吗? (顺便说一句,我决定将循环放在 receiveMessage 中,用于将网络流轮询到 main 函数中,因为任何时候都会出现消息)。

【问题讨论】:

  • 我们是否遗漏了什么?将 while(true), 更改为 while(keepLo​​oping),然后在循环内部,如果您检测到您没有将其设置为 false,线程会优雅地完成????

标签: c# multithreading tcpclient terminate suspend


【解决方案1】:

暂停确实是邪恶的,尤其是在您尝试使用它的方式上——永远停止线程执行。它会留下线程拥有的所有锁,也不会释放资源。

Thread Abort 稍微好一点,因为它至少会尝试终止线程清理器并且锁将有机会被释放。

要正确地做到这一点,你确实需要你的线程代码来配合终止。线程检查的事件、信号量甚至简单的布尔值可能就足够了。

重新设计您的解决方案可能会更好,以便拥有消息队列并在单独的线程上处理它们。特殊消息可能只是清空队列。

【讨论】:

    【解决方案2】:

    在没有可靠方法终止线程的情况下启动线程是一种不好的做法。挂起/中止是终止线程的不可靠方法之一,因为您可能会在破坏整个程序的状态下终止线程,并且您无法避免它发生。

    您可以在此处查看如何安全地终止线程:Killing a .NET thread

    如果“用户”给了你一个在线程中运行的方法,那么用户也应该给你一个方法来阻止代码运行。把它想象成一个契约:你向用户保证你会调用 stop 方法,并且他们承诺 stop 方法实际上会停止线程。如果您的用户违反该合同,那么他们将对出现的问题负责,这很好,因为您不想为用户的错误负责:)。

    请注意,我不能强制函数的程序员捕获 ThreadAbortException。

    由于挂起/中止是不好的做法,程序员不需要捕捉ThreadAbortException,但他们应该捕捉ThreadInterruptedException 作为他们“合同”的一部分。

    请记住,您需要担心两种情况:

    1. 线程正在执行一些代码。
    2. 线程处于阻塞状态。

    如果线程正在执行某些代码,您所能做的就是通知线程它可以退出并等待它处理通知。您也可以跳过等待并假设您已经泄漏了资源,在这种情况下,这又是用户的错,因为他们没有设计他们的 stop 方法来及时终止他们的线程。

    如果线程处于阻塞状态并且它没有阻塞通知构造(即信号量、手动重置事件等),那么您应该调用Thread.Interrupt() 使其脱离阻塞状态——用户必须处理ThreadInterruptedException

    【讨论】:

      【解决方案3】:

      您需要在您的应用程序和function 的来源之间建立某种取消协议。然后您可以在function 和您的消息循环之间共享某种取消令牌。如果消息循环识别出function 需要停止,则通过设置必须在适当情况下由函数测试的令牌来发出信号。最简单的方法是共享一个条件变量,该变量可以在您的消息循环中自动设置并从function 中自动读取。

      不过,我会考虑使用适当的异步 IO 模式以及 .NET 框架开箱即用提供的 Tasks 以及适当的取消机制。

      【讨论】:

      • 我刚刚检查了异步 I/O,它似乎只有在我知道预期哪条消息并且确定没有其他消息可以到达时才有意义。对于我的情况,我需要一直监视和解码传入的消息,并通过杀死一个线程并根据收到的消息启动一个新函数来对它们做出反应。这意味着,即使在回调期间也可能出现消息。还是我在这里看到了问题?
      • 使用异步 IO,您可以在某个端点“注册”传入消息。在没有消息到达之前,您不会消耗 CPU 时间。在新消息上,您的注册客户将被安排并有机会处理该消息。在您作为发件人的角色中,它的工作方式完全相反。这个想法是,总而言之,服务相同数量的请求所需的资源要少得多——当然,如果存在适当的基础设施(例如智能调度程序、异步 IO 功能等)。
      【解决方案4】:

      所以function 是指您几乎无法控制的代码?这是非常典型的 3rd 方库。大多数时候,它们没有内置的能力来优雅地终止长时间运行的操作。由于您不知道这些功能是如何实现的,因此您的选择很少。事实上,您唯一能保证安全的选择是在它们自己的进程中启动这些操作并通过 WCF 与它们通信。这样,如果您需要突然终止操作,您只需终止该进程。杀死另一个进程不会破坏当前进程的状态,就像您在当前进程中的线程上调用 Thread.Abort 时会发生的情况一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-07
        • 1970-01-01
        • 1970-01-01
        • 2019-05-03
        • 2022-11-21
        • 2021-06-30
        相关资源
        最近更新 更多