ndogac
ndogac

Reputation: 1245

AutoResetEvent with Return Value

I am trying to implement an AutoResetEvent that returns a value when it is signaled with its Set method. I tried to use volatile on the isCancelled local variable but that resulted with a syntax error. I don't want to introduce a class field just for this method. So is there a way that I can both set that AutoResetEvent and get the boolean flag to know whether the operation is succeeded or not? Here is my code.

private async Task<bool> GetCancelOrderStatus(Pair pair)
{
    var autoResetEvent = new AutoResetEvent(false);
    var isCancelled = false;

    var options = new SubscribeOptions(SubscribeOptionNames.CancelOrderStatus);
    var subscribe = new Subscribe(new[] { pair }, options);

    await _client.SubscribeAsync(subscribe);

    _client.CancelOrderStatusReceived += (sender, args) =>
    {
        if (args.Message.Status == Status.Ok)
            isCancelled = true;

        autoResetEvent.Set();
    };

    autoResetEvent.WaitOne();

    return isCancelled;
}

Upvotes: 0

Views: 707

Answers (2)

Stephen Cleary
Stephen Cleary

Reputation: 456677

I am trying to implement an AutoResetEvent that returns a value when it is signaled with its Set method.

If you're using one kind of synchronization primitive and find yourself thinking "I want it to do something else", then that's an indication that the incorrect synchronization primitive is being used.

"AutoResetEvent with passing a value from Set to Wait" sounds to me like a producer/consumer queue, e.g., BlockingCollection<T>.

However, the code you posted is interesting. It ends up using a synchronous synchronization primitive from an asynchronous method, which raises a red flag. It seems to me that the SubscribeAsync + CancelOrderStatusReceived methods are a kind of Event-Based Asynchronous Pattern (EAP), and that the code would be made cleaner by converting this to Task-Based Asynchronous Pattern (TAP).

Upvotes: 1

meklarian
meklarian

Reputation: 6625

Your sample looks fine to me except for one thing: You're adding the event handler after waiting for the next subscription event. From here, I infer that SubscribeAsync() should cause _client to enter a state where CancelOrderStatusReceived might get fired; but if you attach the event handler after the await then you will probably miss the event.

Try inverting the two statements, and notwithstanding any other internal activity in _client, it should work.

private async Task<bool> GetCancelOrderStatus(Pair pair)
{
    var autoResetEvent = new AutoResetEvent(false);
    var isCancelled = false;

    var options = new SubscribeOptions(SubscribeOptionNames.CancelOrderStatus);
    var subscribe = new Subscribe(new[] { pair }, options);

    _client.CancelOrderStatusReceived += (sender, args) =>
    {
        if (args.Message.Status == Status.Ok)
            isCancelled = true;

        autoResetEvent.Set();
    };

    await _client.SubscribeAsync(subscribe);

    autoResetEvent.WaitOne();

    return isCancelled;
}

Also, you might find that you don't even need the AutoResetEvent if the event CancelOrderStatusReceived is only fired during the time spent awaiting SubscribeAsync for this operation.

Upvotes: 1

Related Questions