0

编辑:这似乎是一个症结所在,所以我将把它排除在外:

我没有使用它进行同步。只是在不再需要/可取时终止长时间运行的任务。
假设:假设这些线程只是简单地写入控制台(比如:“线程 1”),休眠一个随机长度,然后退出。如果他们被中止,我希望他们通过另一个控制台写入通知我(比如:“线程 1 中止”)。如果我在运行之前尝试中止它,我希望能够直接跳转到中止代码,而没有任何机会执行其正常功能。如果它在正常运行期间中止,它当然会同时打印两者。


我有一大堆线程我希望在一个运行 .NET 2.0 和 Visual Studio 2008 的 ASP 站点上按顺序运行(不知道这有多重要,但它就在那里),它们可能已经中止清理代码无论他们的任务有多远,都应该运行它。所以我做了一个这样的线程:

Thread t = new Thread(delegate() {
   try { 
      /* do things */ 
      System.Diagnostics.Debug.WriteLine("try");
   }
   catch (ThreadAbortException) {
      /* cleanup */ 
      System.Diagnostics.Debug.WriteLine("catch");
   }
});

现在,如果我希望在中途中止线程集,那么以后可能仍然需要进行清理。查看 MSDN 意味着您可以 .Abort() 一个尚未启动的线程,然后 .Start() 它,此时它将接收异常并正常执行。或者您可以 .Join() 中止的线程等待它完成中止。大概你可以将它们结合起来。

http://msdn.microsoft.com/en-us/library/ty8d3wta(v=VS.80).aspx
要等到线程中止,您可以在调用 Abort 方法后在线程上调用 Join 方法,但是不能保证等待会结束。
如果在尚未启动的线程上调用 Abort,则调用 Start 时线程将中止。如果在阻塞或休眠的线程上调用 Abort,则该线程将被中断然后中止。

现在,当我调试并逐步执行此代码时:

t.Abort(); // ThreadState == Unstarted | AbortRequested
t.Start(); // throws ThreadStartException: "Thread failed to start."
// so I comment it out, and
t.Join(); // throws ThreadStateException: "Thread has not been started."

在任何时候我都看不到任何输出,也没有到达 try 或 catch 块上的任何断点。
奇怪的是,ThreadStartException 没有被列为 .Start() 的可能抛出,从这里:http: //msdn.microsoft.com/en-us/library/a9fyxz7d (v=VS.80).aspx (或任何其他版本)

我知道这可以通过使用 start 参数来避免,该参数说明线程是否应该跳转到清理代码,并在 Abort 调用之前(这可能是我要做的)。我可以.Start() 线程,然后 .Abort() 它。但是由于 .Start 和 .Abort 之间的时间不确定,我认为它不可靠,并且文档似乎说我的原始方法应该有效。

我错过了什么吗?文档有错吗?

编辑:哦。而且你不能在非参数化的线程(开始)上调用 .Start(参数)。除了反复试验,有没有办法找出线程是否被参数化?我看到了一个私人 m_Delegate,但没有公开...

4

2 回答 2

3

使用时...

t.Abort();
t.Start();

... ThreadStartExcpetion 的 innerException 将包含 ThreadAbortExeption,正如 msdn 所述:(如果在尚未启动的线程上调用 Abort,则调用 Start 时线程将中止

如果你执行...

t.Start();
t.Abort();

... ThreadAbortException 可能永远不会发生,因为线程在中止之前没有时间启动。

如果您测试类似...

t.Start();
Thread.Sleep(100);
t.Abort();

...应该始终执行“清理”代码。

如果您需要执行清理代码,即使线程还没有开始做任何事情,一个可能的解决方案是启动清理方法和 Abort 调用。

此外,您应该尽量避免中止线程并使用不同的技术(http://msdn.microsoft.com/en-us/library/ms228964.aspx)

于 2011-01-03T20:57:42.790 回答
0

我意识到文档对您的暗示,但事实并非如此。如果你中止一个线程然后启动它,它永远不会以任何方式执行。CLR 足够聪明,知道线程中止是一项不稳定的业务,因此不能错过完全跳过线程执行的机会。

也许将您的清理代码变成一个子例程。如果父线程中止或知道中止,它会显式调用清理代码。

请记住,.net 在中止线程后“清理”的概念是卸载正在执行中止线程的程序集的 appdomain。这是另一种说法,“不要指望这能很好地清理干净”。您应该首先始终寻求不需要中止线程的设计。

于 2011-01-03T20:44:25.130 回答