11

I need to change current code to not block current thread when EventWaitHandle.WaitOne is called. Problem is that I am awaiting system-wide event. I did not find any proper replacement yet.

Code:

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(" ");
        }

I need app to continue and not stop on the line where I call WaitOne, ideally there would be await. How can I implement this ?

frno
  • 1,064
  • 11
  • 24
  • So why are you calling WaitOne in the first place if you do not wish to wait? I do not understand what you want to happen. – usr Jun 09 '14 at 12:46
  • I deleted my answer as you need a system-wide implementation which i overlooked – Yuval Itzchakov Jun 09 '14 at 12:46
  • What behavior are you looking for? Do you want your application to continue executing, and be notified when the other application is fully loaded (or when the 45 seconds elapses)? – Jim Mischel Jun 09 '14 at 14:06
  • Check out [ThreadPool.RegisterWaitForSingleObject](http://msdn.microsoft.com/en-us/library/02x3daw5(v=vs.110).aspx), which has a working example. The `waitObject` you pass can be a system-wide object (a global `EventWaitHandle`, for example). – Jim Mischel Jun 09 '14 at 14:13
  • Whis was original code which I need to rewrite. It was good when we had it at the end of app1, but we moved that code to launch sooner because second app takes too long to load. Then the blockage from wait handle is a problem – frno Jun 10 '14 at 13:15
  • Yes I believe I have made a successful try with RegisterWaitForSingleObject yesterday, I found some code in MSDN that seems to help, I am awaiting verification – frno Jun 10 '14 at 13:16

1 Answers1

15

You can use AsyncFactory.FromWaitHandle, in my AsyncEx library:

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

The implementation uses 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;
}
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • thanks, I used pretty much code as you are writing in second code block. Using additional non-.NET framework libs is discouraged in the project – frno Jun 10 '14 at 13:20
  • If I call this method 10 times (without a timeout), will I then have consumed 10 threadpool threads that are now blocking while waiting for the signal to be set? – LaFleur Jun 10 '15 at 03:55
  • 2
    @LaFleur: No, the `RegisterWaitForSingleObject` is able to coalesce calls; IIRC up to 31 handles can be waited on by a single thread pool thread. Not sure what the behavior is if you use the same handle. – Stephen Cleary Jun 10 '15 at 12:23