Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何有效地终止C#中的线程?_C#_.net_Multithreading_.net 3.5 - Fatal编程技术网

如何有效地终止C#中的线程?

如何有效地终止C#中的线程?,c#,.net,multithreading,.net-3.5,C#,.net,Multithreading,.net 3.5,我不是一个。我已经阅读了关于杀线程的所有建议,但是请考虑代码。它做了以下工作: 它启动一个线程(通过StartThread方法) 它调用数据库以查找ServiceBroker队列中的任何内容。注意WAITFOR命令-它意味着它将一直坐在那里,直到队列中有东西。所有这些都在MonitorQueue方法中 终止线程。我尝试了。中断——似乎什么也没做。然后我尝试了.Abort,它永远不应该被使用,但即使这样也没用 Thread thxMonitor = new Thread(MonitorQueue)

我不是一个。我已经阅读了关于杀线程的所有建议,但是请考虑代码。它做了以下工作:

  • 它启动一个线程(通过
    StartThread
    方法)
  • 它调用数据库以查找ServiceBroker队列中的任何内容。注意
    WAITFOR
    命令-它意味着它将一直坐在那里,直到队列中有东西。所有这些都在
    MonitorQueue
    方法中
  • 终止线程。我尝试了
    。中断
    ——似乎什么也没做。然后我尝试了
    .Abort
    ,它永远不应该被使用,但即使这样也没用

    Thread thxMonitor = new Thread(MonitorQueue);
    void StartThread() {
        thxMonitor.Start();
    }
    
    void MonitorQueue(object obj) {
        var conn = new SqlConnection(connString);
        conn.Open();
        var cmd = conn.CreateCommand();
        cmd.CommandTimeout = 0; // forever and ever
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "WAITFOR (RECEIVE CONVERT(int, message_body) AS Message FROM SBQ)";
    
        var dataTable = new DataTable();
        var da = new SqlDataAdapter(command);
    
        da.Fill(dataTable);
        da.Dispose();
    }
    
    void KillThreadByAnyMeansNecessary() {
        thxMonitor.Interrupt();
        thxMonitor.Abort();
    }
    

  • 实际上可以终止线程吗?

    立即终止线程并不容易。与此相关的潜在问题有:

    你的线程获得一个锁,然后在释放锁之前杀死它。现在需要锁的螺纹将被卡住

    您可以使用一些全局变量来通知线程停止。您必须在线程代码中手动检查该全局变量,如果您看到它指示您应该停止,则返回该变量

    请参考这个问题,讨论同样的问题:
    我讨厌不回答你的问题,但不妨考虑一下另一种方式。T-SQL允许使用WAITFOR指定超时参数,这样,如果在某个时间段内未收到消息,则该语句将退出并必须重试。你会看到这一点,并再次在模式中,你必须等待。折衷的办法是,当线程被请求时,您不会立即让线程停止运行——您必须等待超时过期,然后线程才会停止运行

    您希望这种情况发生得越快,超时间隔就越小。希望它立即发生吗?那么你应该改为投票

    static bool _quit = false;
    
    Thread thxMonitor = new Thread(MonitorQueue);
    void StartThread() {
        thxMonitor.Start();
    }
    
    void MonitorQueue(object obj) {
    
        var conn = new SqlConnection(connString);
        conn.Open();
        var cmd = conn.CreateCommand();
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "WAITFOR (RECEIVE CONVERT(int, message_body) AS Message FROM SBQ) TIMEOUT 500";
    
        var dataTable = new DataTable();    
    
        while(!quit && !dataTable.AsEnumerable().Any()) {
            using (var da = new SqlDataAdapter(command)) {    
                da.Fill(dataTable);
            }
        }
    }
    
    void KillThreadByAnyMeansNecessary() {
        _quit = true;
    }
    
    编辑

    虽然这感觉像是轮询队列,但实际上并非如此。当您进行投票时,您正在积极地检查某些内容,然后等待以避免出现“旋转”情况,即您不断地消耗CPU(尽管您甚至不等待)

    考虑一下在轮询场景中检查条目时会发生什么,然后等待500毫秒。如果队列中没有任何内容,200毫秒后消息到达,则在轮询获取消息时,您必须再等待300毫秒。在超时情况下,如果消息在“wait”方法超时200毫秒后到达,消息将立即得到处理


    轮询时的等待与在紧循环中轮询时的持续高CPU强制的时间延迟是轮询通常不令人满意的原因。等待超时并没有这样的缺点——唯一的折衷办法是在线程死亡之前必须等待超时过期。

    不要终止线程,而是将代码更改为使用带有小超时的WAITFOR

    超时时间过后,检查线程是否已中断

    如果没有,请回过头来再次等待


    是的,“等待的全部意义”就是等待。但是如果你想让某个线程响应,你不能要求一个线程等待无穷大,然后期望它监听其他任何内容。

    设置一个中止标志,告诉线程需要终止。将虚拟记录附加到ServiceBroker队列。等待然后返回。然后线程检查其“Abort”标志,发现它已设置,从队列中删除虚拟记录并退出


    另一种变体是在ServiceBroker监视的表的规范中添加一个“真实”的毒药丸记录——一个非法的记录号,等等。这将完全避免以任何直接的方式接触线程-这总是一件好事:)这可能会更复杂,特别是如果每个工作线程都需要在实际终止时发出通知,但如果工作线程、ServiceBroker和DB都位于不同的框中,这仍然是有效的。我把它作为一个编辑添加进来,因为考虑了更多,毕竟,如果线程通常只通过网络进行通信,那么它看起来更灵活。DB,为什么不用DB关闭它们?没有中止(),没有中断(),希望没有生成Join()的锁定。

    不要这样做!说真的

    要杀死线程,需要调用的函数是函数,可以通过p/Invoke调用该函数。关于不应该使用此方法的所有原因都在文档中

    TerminateThread是一个危险的函数,只能在最极端的情况下使用如果需要,则应调用TerminateThread 确切地知道目标线程正在做什么,您就可以控制所有的线程 目标线程当时可能正在运行的代码 终止的时间。例如,TerminateThread会导致 以下问题:

    • 如果目标线程拥有关键部分,则不会释放该关键部分
    • 如果目标线程正在从堆中分配内存,则不会释放堆锁
    • 如果目标线程在终止时正在执行某些kernel32调用,则该线程进程的kernel32状态可能为 前后矛盾
    • 如果目标线程正在操作共享DLL的全局状态,则DLL的状态可能会被破坏,从而影响其他线程 DLL的用户
    需要注意的重要一点是粗体部分,以及在CLR/.Net框架下,如果您确切地知道目标线程正在做什么(除非您碰巧编写了CLR),那么在这种情况下,您就永远不会

    为了澄清这一点,在运行.Net代码的线程上调用TerminateThread很可能会使进程死锁,或者使进程处于完全不可恢复的状态

    如果你找不到终止连接的方法,那么你最好让线程在后台运行,而不是试图终止连接