合理使用C#中的线程?

时间:2009-03-27 19:07:11

标签: c# multithreading

作为大型自动化流程的一部分,我们正在调用第三方API,它可以在另一台计算机上调用服务。我们最近发现,当其他计算机不可用时,API调用有时会在尝试连接到远程服务器时旋转40分钟。

我们正在使用的API没有提供指定超时的方法,我们不希望我们的程序等待那么久,所以我认为线程是一种很好的方法来强制执行超时。生成的代码如下所示:

 Thread _thread = new Thread(_caller.CallServices());

 _thread.Start();
 _thread.Join(timeout);

 if (_thread.IsAlive)
 {
      _thread.Abort();
      throw new Exception("Timed-out attempting to connect.");
 }

基本上,我想让APICall()运行,但是如果它在超时过后仍然存在,则假设它将失败,将其终止并继续前进。

由于我刚接触C#和.net运行时的线程,我以为我会问两个相关的问题:

.net库中是否有更好/更合适的机制用于我正在尝试做的事情,并且我在那段代码中提交了任何线程陷阱吗?

5 个答案:

答案 0 :(得分:5)

Thread.Abort()是线程中止的请求,并不保证它会及时执行。它也被认为是不好的做法(它会在被中止的线程中抛出线程中止异常,但看起来第三方API似乎没有其他选择。

如果您(以编程方式)知道远程服务主机的地址,则应在将控制权转移到第三方API之前对其进行ping操作。

如果不使用backgroundworker,可以将线程的IsBackgroundThread设置为true,这样就不会阻止程序终止。

答案 1 :(得分:3)

糟糕的主意。 Thread.Abort不一定能清除这种中断的API调用留下的混乱。

如果调用很昂贵,请考虑编写一个单独的执行调用的.exe,并使用命令行或临时文件将参数传递给它/从中传递参数。你可以比杀死一个线程更安全地杀死.exe。

答案 2 :(得分:3)

您也可以只使用委托...为执行工作的方法创建委托,然后在委托上调用BeginInvoke,向其传递参数,并使用回调函数来处理返回值(如果需要) ... 在BeginInvoke之后,您可以等待指定的时间让异步委托完成,如果它没有在指定的时间内继续,则继续......

   public delegate [ReturnType] CallerServiceDelegate
          ([parameter list for_caller.CallService]);

   CallerServiceDelegate callSvcDel = _caller.CallService;
   DateTime cutoffDate = DateTime.Now.AddSeconds(timeoutSeconds);
   IAsyncResult aR = callSvcDel.BeginInvoke([here put parameters], 
                                             AsynchCallback, null); 
   while (!aR.IsCompleted && DateTime.Now < cutoffDate)
       Thread.Sleep(500);
   if (aR.IsCompleted)
   {
      ReturnType returnValue = callSvcDel.EndInvoke(aR);
      // whatever else you need to do to handle success
   }
   else
   {
      callSvcDel.EndInvoke(aR);
      // whatever you need to do to handle timeout
   }

注意:由于编写的AsynchCallback可能为null,因为代码从EndInvoke()中检索返回值,但是如果您愿意,可以让CallService()方法调用AsynchCallback委托并将返回值传递给它。 ..

答案 3 :(得分:0)

它可能有用,但没有人能够在不了解第三方API的情况下肯定地说。像这样中止线程可能会使组件处于无法恢复的某种无效状态,或者它可能不会释放它分配的资源(想想 - 如果你的一个例程刚刚停止执行中途,那该怎么办?你能对你的计划所处的状态做出任何保证吗?)。

正如Cicil建议的那样,首先ping服务器可能是个好主意。

答案 4 :(得分:0)

您的应用程序是长时间运行还是更像是按需运行的应用程序?如果是后者,我个人会考虑使用Thread.Abort()选项。虽然从纯粹主义者的角度来看它可能不是最理想的(资源管理等),但实施起来肯定是直截了当的,并且考虑到你的特定应用程序的工作方式,它可能会受到影响。

单独的可执行文件的想法是有道理的。也许另一种选择是使用AppDomains。我不是这方面的专家(我欢迎对此进行改进/更正),但据我了解,您将API调用放在单独的DLL中并将其加载到单独的AppDomain中。当API调用完成或您必须中止它时,您可以将DLL与DLL一起卸载。这个可能具有清理直接Thread.Abort()所不具备的资源的额外好处。