Anw*_*dra 41 c# multithreading timeout
我有obj第三方组件的对象,
// this could take more than 30 seconds
int result = obj.PerformInitTransaction();
Run Code Online (Sandbox Code Playgroud)
我不知道里面发生了什么.我所知道的是,如果需要更长的时间,那就失败了.
如何为此操作设置超时机制,以便如果超过30秒我只是抛出MoreThan30SecondsException?
Pao*_*sco 73
您可以在单独的线程中运行该操作,然后在线程连接操作上设置超时:
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.");
}
}
}
Run Code Online (Sandbox Code Playgroud)
Col*_*nic 13
更简单地使用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");
Run Code Online (Sandbox Code Playgroud)
如果您不想阻止主线程,可以使用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();
}
Run Code Online (Sandbox Code Playgroud)
Jon Skeet有一种不那么有力的方式(优雅地关闭工作线程)停止线程而不是中止.
但是,由于您无法控制操作PerformInitTransaction(),因此当Abort失败并使对象处于无效状态时,您无法做很多事情.如上所述,如果你能够清除任何中止PerformInitTransaction悬挂的东西,你可以通过抓住来做到这一点ThreadAbortException,虽然这是第三方通话,但这意味着猜测你已经离开他们的方法的状态.
该PerformInitTransaction确实应该是一个提供超时.
小智 5
以下是两个实现,它们也会抛出内部任务中发生的任何异常。
对于操作(无返回值):
public static bool DoWithTimeout(Action action, int timeout)
{
Exception ex = null;
CancellationTokenSource cts = new CancellationTokenSource();
Task task = Task.Run(() =>
{
try
{
using (cts.Token.Register(Thread.CurrentThread.Abort))
{
action();
}
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
ex = e;
}
}, cts.Token);
bool done = task.Wait(timeout);
if (ex != null)
throw ex;
if (!done)
cts.Cancel();
return done;
}
Run Code Online (Sandbox Code Playgroud)
对于 Func(有返回值):
public static bool DoWithTimeout<T>(Func<T> func, int timeout, out T result)
{
Exception ex = null;
result = default(T);
T res = default(T);
CancellationTokenSource cts = new CancellationTokenSource();
Task task = Task.Run(() =>
{
try
{
using (cts.Token.Register(Thread.CurrentThread.Abort))
{
res = func();
}
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
ex = e;
}
}, cts.Token);
bool done = task.Wait(timeout);
if (ex != null)
throw ex;
if (done)
result = res;
else
cts.Cancel();
return done;
}
Run Code Online (Sandbox Code Playgroud)