更好的同步操作超时检测

rep*_*pka 5 c# timeout synchronous begininvoke threadpool

我需要一种同步执行某些操作的方法,该操作应在半秒内完成,但可能只会停留几分钟。如果超时我不在乎结果。这是我现在正在使用编译器生成的 delegate.BeginInvoke 执行的操作:

static void Main()
{
    bool disposed = false;
    var wait = new ManualResetEvent(false);
    var a = new Action(
        () =>
            {
                Thread.Sleep(1000); // <- some looong action

                if (!disposed)
                    lock (wait)
                        if (!disposed)
                            wait.Set();
            });

    a.BeginInvoke(a.EndInvoke, null);

    bool success = wait.WaitOne(500);
    Console.WriteLine(success ? "success" : "timeout");

    lock (wait)
    {
        wait.Dispose();
        disposed = true;
    }

    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

看起来很丑。我知道 lambda 闭包的disposed变量已被修改(与我的 ReSharper 不同,我喜欢这个 C# 功能)。一切都是因为我想处置掉ManualResetEvent。您能建议 .NET4 中更好的方法吗?也许我应该跳过处理事件并依赖 GC?

需要注意的是:ManualResetEvent.Set()如果您尝试在已处置的实例上执行此操作,则会爆炸。

rep*_*pka 3

呃,现在我更多地查看了使用编译器生成的代码示例,delegate.BeginInvoke我发现它返回的结果完全IAsyncResult符合AsyncWaitHandle我的目标:

var a = new Action(() => Thread.Sleep(1000)); // <- some looong action
IAsyncResult asyncResult = a.BeginInvoke(a.EndInvoke, null);
bool success = asyncResult.AsyncWaitHandle.WaitOne(500);
Run Code Online (Sandbox Code Playgroud)

实际上,该等待句柄是当我的异步调用完成时从线程池线程自动处置的AsyncResult一个实例。ManualResetEvent

  • 是的。但没有什么真正的区别,只有 EndInvoke() 可以处理它。如果等待超时,您将无法调用该方法。不用担心,与您一直运行的线程相比,内核事件非常便宜且微不足道。 (2认同)