【问题标题】:Set thread lifetime at startup在启动时设置线程生命周期
【发布时间】:2013-11-12 20:28:57
【问题描述】:

当你启动线程时,有没有办法设置一个线程应该(最大)存活多长时间?

换一种说法,用“伪代码”,有没有这样的:

Thread t = new Thread();
t.start();
t.abort_after_x_seconds(30);

如果线程存活超过 30 秒,这将使线程中止。

编辑:我仍然无法让它工作,我最初拥有的是:

while(true)
{
    if(...)
    {
        Thread t = new Thread(new ThreadStart(startMethod));
        t.start();
    }
    Thread.sleep(...);
}

问题是有时线程会挂起(我没有实现线程的作用,所以我不知道确切原因(这是一个学校项目,我们在组织方面是菜鸟)),所以我想杀死那些线程。我尝试使用以下示例中的 Tasks 和 CancellationTokens,但是当 Task 挂起时 它无法检查是否发生了取消请求。

【问题讨论】:

  • 中止线程不是一个好习惯(Thread.Abort() 已被弃用,并且在任何情况下都不起作用)...您为什么要这样做?必须有一个好的模式来代替那个。
  • 您在线程内是否有一些长时间的操作?如果是这样,是否可以为该操作设置超时?
  • 您尝试在哪个上下文中使用此功能?提供更多上下文。该线程将执行什么很重要。

标签: c# multithreading lifecycle


【解决方案1】:
  1. 大多数时候,您不应该使用Threads,而是使用Tasks。它们更方便、更高效。
  2. 中止某些内容并不安全,您应该改用合作取消。如果您正在调用支持取消的方法,则只需向其传递一个取消令牌,该令牌将在 30 秒后取消。

因此您的代码可能如下所示(使用 .Net 4.5):

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)));
var task = Task.Run(() => YourMethod(cts.Token), cts.Token);

【讨论】:

  • 好多了:) 但是,即使您取消任务 - 您也需要确保您正在执行的操作被优雅地中止/取消
  • @Ahmedilyas 这是被调用方法的工作,而不是调用者的工作。
【解决方案2】:

[编辑:我的反应太慢了。但我将把它留在这里作为示例代码。]

您应该为此使用合作取消。线程本身需要检测何时应该退出,并做出适当的响应。

有一个叫做CancellationToken 的东西是从CancellationTokenSource 生成的,您可以将其用于此目的。

甚至还有一个 CancellationTokenSource 构造函数可以让您设置超时。

这里有一些示例代码来演示它的使用:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace Demo
{
    class Program
    {
        private void run()
        {
            using (var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
            {
                var task = Task.Run(() => exampleOne(tokenSource.Token));
                task.Wait();
            }

            using (var tokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
            {
                var task = Task.Run(() => exampleTwo(tokenSource.Token));
                task.Wait();
            }

            Console.WriteLine("Done.");
        }

        static void exampleZero()
        {
            Console.WriteLine("Starting exampleZero()");

            try
            {
                Thread.Sleep(10000); // Simulate work.
            }

            catch (OperationCanceledException)
            {
                Console.WriteLine("Operation cancelled.");
            }

            Console.WriteLine("Exiting exampleZero()");
        }

        static void exampleOne(CancellationToken cancellation)
        {
            Console.WriteLine("Starting exampleOne()");

            // Busy loop processing.

            while (!cancellation.IsCancellationRequested)
            {
                // Do some work.
            }

            Console.WriteLine("Exiting exampleOne()");
        }

        static void exampleTwo(CancellationToken cancellation)
        {
            Console.WriteLine("Starting exampleTwo()");

            while (!cancellation.WaitHandle.WaitOne(100)) // Wait 100ms between work.
            {
                // Do some work.
            }

            Console.WriteLine("Exiting exampleTwo()");
        }

        static void Main()
        {
            new Program().run();
        }
    }
}

【讨论】:

    【解决方案3】:

    正如评论者所说,使用Abort 是不好的做法,不能保证立即中止。 你为什么要保持线程活着?当分配给它的任务完成时,线程将被释放回池中。下次在线程上运行任务时,将通过创建另一个新线程或重新使用线程池中可用的线程池自动从线程池中获得。

    听起来您的逻辑/代码很糟糕,需要修复而不是等待 x 秒然后终止它,这本身会导致问题。

    也许您需要一个计时器,它可以在 30 秒后计时,然后您可以禁用计时器并终止手头的任务。

    【讨论】:

    • 不推荐使用Abort 的任何资源?
    • @SriramSakthivel = 我很抱歉。我编辑了我的评论,因为我同时在想别的。它没有被弃用,但也不是一个好的做法。 msdn.microsoft.com/en-us/library/ty8d3wta(v=vs.110).aspx
    • @svick - 对。抱歉,我在不同的上下文中使用该线程(该死的英语与编程英语)
    • Thread.Abort 没有被弃用,虽然中止线程肯定有问题,不应该在没有考虑到像 ASP.NET 这样的框架实际上是围绕中止线程来结束请求而构建的。
    猜你喜欢
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 2022-06-12
    • 2012-08-06
    • 2021-02-03
    • 2011-04-11
    • 2016-09-08
    • 1970-01-01
    相关资源
    最近更新 更多