C#中线程的合理使用?

C#中线程的合理使用?,c#,multithreading,C#,Multithreading,作为大型自动化过程的一部分,我们正在调用第三方API,该API可以在另一台机器上调用服务。我们最近发现,当另一台机器不可用时,API调用有时会在尝试连接到远程服务器时旋转长达40分钟 我们正在使用的API没有提供一种指定超时的方法,我们也不希望我们的程序等待那么长时间,所以我认为线程将是强制执行超时的好方法。生成的代码如下所示: Thread _thread = new Thread(_caller.CallServices()); _thread.Start(); _thread.Jo

作为大型自动化过程的一部分,我们正在调用第三方API,该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库中是否有更好/更合适的机制来执行我正在尝试的操作,以及我是否在这段代码中提交了任何线程问题?

坏主意。中止并不一定会清除这样一个中断的API调用所留下的混乱

如果调用很昂贵,请考虑编写一个单独的.EXE来进行调用,并使用命令行或临时文件将参数传递给/从它传递。杀死一个.exe比杀死一个线程安全得多。

thread.Abort()是一个要求线程中止的请求,不能保证它会及时中止。这也被认为是错误的做法(它会在被中止的线程中引发线程中止异常,但第三方API似乎没有为您提供其他选择)

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


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

它可能会工作,但在不了解第三方API的情况下,没有人可以肯定。像这样中止线程可能会使组件处于某种无效状态,它可能无法运行ecover,或者它不会释放它分配的资源(想想——如果你的一个例程中途停止执行会怎么样。你能保证你的程序将处于什么状态吗?)


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

您也可以使用委托…为执行该工作的方法创建一个委托,然后对委托调用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
   }
public委托[ReturnType]调用服务委托
([u caller.CallService的参数列表];
CallerServiceDelegate callSvcDel=\u caller.CallService;
DateTime截止日期=DateTime.Now.AddSeconds(timeoutSeconds);
IAsyncResult aR=callSvcDel.BeginInvoke([此处放置参数],
AsynchCallback,空);
而(!aR.IsCompleted&&DateTime.Now

注意:编写时AsynchCallback可以为null,因为代码从EndInvoke()检索返回值,但如果需要,可以使用CallService()方法调用asyChelCub委托并将返回值设置为……< /p> < p>您的应用程序运行了很长一段时间,还是更多的是按需运行的应用程序?如果是后者,我个人会考虑使用Toel.Babter()选项,而从纯粹主义者的角度来看,这可能不是最理想的。(资源管理等),这当然是很容易实现的,而且考虑到您的特定应用程序的工作方式,它可能会承担费用


一个单独的可执行文件的想法是有意义的。也许另一个选择是使用AppDomains。我不是这方面的专家(我欢迎对此进行改进/更正),但据我所知,您应该将API调用放在一个单独的DLL中,并将其加载到一个单独的AppDomain中。当API调用完成或您必须中止它时,您可以将AppDomain与DLL一起卸载。这可能还有一个额外的好处,那就是清理直接线程无法使用的资源。abort()不会。

您如何处理超时?您是否让组件继续尝试连接到丢失的服务器长达40分钟?我想问题是如何使组件停止尝试连接。抱歉,正在编辑以添加示例代码…超时问题由日期时间解决。现在<中的截止日期while条件