【问题标题】:Rework EventWaitHandle to asynchronously await signal重做 EventWaitHandle 以异步等待信号
【发布时间】:2014-06-09 11:33:13
【问题描述】:

当调用 EventWaitHandle.WaitOne 时,我需要更改当前代码以不阻塞当前线程。问题是我正在等待系统范围的事件。我还没有找到合适的替代品。

代码:

EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset, "Local event", out screenLoadedSignalMutexWasCreated);

        StartOtherApp();

        if (screenLoadedSignalMutexWasCreated)
        {
            isOtherAppFullyLoaded = handle.WaitOne(45000, true);

            if (isOtherAppFullyLoaded )
            {
                // do stuff
            }
            else
            {
                // do stuff
            }

            handle.Dispose();
            signalingCompleted = true;
        }
        else
        {
            isOtherAppFullyLoaded = false;
            throw new Exception(" ");
        }

我需要应用程序继续运行,而不是在我调用 WaitOne 的线路上停止,理想情况下会有等待。我该如何实现呢?

【问题讨论】:

  • 那么,如果您不想等待,为什么要首先调用 WaitOne?我不明白你想要发生什么。
  • 我删除了我的答案,因为你需要一个我忽略的系统范围的实现
  • 您在寻找什么行为?您是否希望您的应用程序继续执行,并在另一个应用程序完全加载(或 45 秒过去)时收到通知?
  • 查看ThreadPool.RegisterWaitForSingleObject,它有一个工作示例。您传递的waitObject 可以是系统范围的对象(例如,全局EventWaitHandle)。
  • 这是我需要重写的原始代码。当我们在 app1 结束时拥有它时很好,但是我们移动了该代码以更快地启动,因为第二个应用程序加载时间太长。那么等待句柄的阻塞是个问题

标签: c# multithreading asynchronous


【解决方案1】:

你可以使用AsyncFactory.FromWaitHandle,在我的AsyncEx library

isOtherAppFullyLoaded = await AsyncFactory.FromWaitHandle(handle,
    TimeSpan.FromMilliseconds(45000));

实现使用ThreadPool.RegisterWaitForSingleObject:

public static Task<bool> FromWaitHandle(WaitHandle handle, TimeSpan timeout)
{
    // Handle synchronous cases.
    var alreadySignalled = handle.WaitOne(0);
    if (alreadySignalled)
        return Task.FromResult(true);
    if (timeout == TimeSpan.Zero)
        return Task.FromResult(false);

    // Register all asynchronous cases.
    var tcs = new TaskCompletionSource<bool>();
    var threadPoolRegistration = ThreadPool.RegisterWaitForSingleObject(handle,
        (state, timedOut) => ((TaskCompletionSource<bool>)state).TrySetResult(!timedOut),
        tcs, timeout);
    tcs.Task.ContinueWith(_ =>
    {
        threadPoolRegistration.Dispose();
    }, TaskScheduler.Default);
    return tcs.Task;
}

【讨论】:

  • 谢谢,我用了很多代码,就像你在第二个代码块中写的一样。不鼓励在项目中使用其他非 .NET 框架库
  • 如果我调用这个方法 10 次(没有超时),那么我是否会消耗 10 个线程池线程,这些线程现在在等待信号设置时阻塞?
  • @LaFleur:不,RegisterWaitForSingleObject 能够合并呼叫; IIRC 单个线程池线程最多可以等待 31 个句柄。如果您使用相同的句柄,则不确定行为是什么。
猜你喜欢
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 2017-11-02
  • 1970-01-01
  • 2023-03-12
  • 2020-11-24
  • 2014-02-20
  • 2021-12-30
相关资源
最近更新 更多