2010-02-15 245 views
34

我有对象obj这是第三方组件,超时设置为操作

// this could take more than 30 seconds 
int result = obj.PerformInitTransaction(); 

我不知道里面是什么发生。 我知道的是,如果需要更长的时间,那就失败了。

如何设置一个超时机制来执行这个操作,这样如果需要30秒以上的时间我只需要扔MoreThan30SecondsException

回答

66

你可以在一个单独的线程中运行的操作,然后把超时的线程上的连接操作:

using System.Threading; 

class Program { 
    static void DoSomething() { 
     try { 
      // your call here... 
      obj.PerformInitTransaction();   
     } catch (ThreadAbortException) { 
      // cleanup code, if needed... 
     } 
    } 

    public static void Main(params string[] args) { 

     Thread t = new Thread(DoSomething); 
     t.Start(); 
     if (!t.Join(TimeSpan.FromSeconds(30))) { 
      t.Abort(); 
      throw new Exception("More than 30 secs."); 
     } 
    } 
} 
+1

@Bomboca:我回滚您的编辑时,'Exception'我要把不应该是'ThreadAbortException',这点是由CLR时,抛出通话到“中止”。 –

+0

对不起,感谢您的输入:) –

+2

这是一个阻塞呼叫,如果你需要主线程在这个时候做其他事情,这将无法正常工作! – feldeOne

1

你可以看看在一个线程,并在超时调用方法,中止线程,引发异常。此外,在这种情况下,您必须处理ThreadBorted异常。

+0

您对ThreadAbortedException +1正确。 –

0

有一个很好的例子,通用的解决方案使用帮助类here

它使用Action委托来避免前面示例中显示的线程创建/销毁。

我希望这会有所帮助。

2

您需要小心中止这样的操作,特别是因为它在第三方组件中,您(可能)无法访问要修改的代码。

如果您中止操作,那么您将不会知道您已经将底层类留在了什么状态。例如,它可能已获取锁,并且您的约会导致该锁未被释放。即使您在中止操作后销毁对象,它也可能已经改变了一些全局的状态,因此如果不重新启动,您将无法可靠地创建新实例。

6

如果您不希望阻止您可以使用主线程System.Threading.Timer

private Thread _thread; 

void Main(string[] args) 
{ 
    _thread = new ThreadStart(ThreadEntry); 
    _thread.Start(); 
    Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite); 
} 


void ThreadEntry() 
{ 
    int result = obj.PerformInitTransaction(); 
} 

void TimeOut(object state) 
{ 
    // Abort the thread - see the comments 
    _thread.Abort(); 

    throw new ItTimedOutException(); 
} 

乔恩斯基特有停止线比中止的力度较小的方式(Shutting Down Worker Threads Gracefully)。

但是,由于您无法控制操作PerformInitTransaction()正在执行,因此当Abort失败并使对象处于无效状态时,您可以做的事情不多。如上所述,如果您可以清理任何中止PerformInitTransaction中止的事件,则可以通过捕获ThreadAbortException来完成此操作,但由于它是第三方调用,这意味着要猜测您已将方法留在的状态。

PerformInitTransaction应该确实是提供暂停的那个。

10

更简单地使用Task.Wait(TimeSpan)

using System.Threading.Tasks; 

var task = Task.Run(() => obj.PerformInitTransaction()); 
if (task.Wait(TimeSpan.FromSeconds(30))) 
    return task.Result; 
else 
    throw new Exception("Timed out"); 
+0

这是非常简单的,自.NET 4.0起可用。 –

+0

这不会杀死线程 –