Brandon Moore
Brandon Moore

Reputation: 8780

Putting synchronous wrapper over asynchronous methods

I'm integrating with a PIN device with an api containing asynchronous methods. For example one of them is called GetStatus and it raises a DeviceStateChangedEvent with the state passed into it as a parameter.

I'd like to have an interface that is not asynchronous over it though, so that when I call GetStatus on my interface it will actually return the status rather than raising an event to pass that data to me.

I'm thinking I could do something like this:

public class MSRDevice
{
    StatusInfo _status;
    bool _stateChangedEventCompleted = false;
    IPAD _ipad; // <-- the device

    public MSRDevice()
    {
        //Initialize device, wire up events, etc.
    }

    public StatusInfo GetStatus()
    {
        _ipad.GetStatus() // <- raises StatusChangedEvent
        while(!_stateChangedEventCompleted);
        _stateChangedEventCompleted = false;
        return _status;
    }

    void StateChangedEvent(object sender, DeviceStateChangeEventArgs e) 
    {
         _status = e.StatusInfo;
    }
}

Is this a good way to address this or this there a better solution?

Upvotes: 1

Views: 1272

Answers (2)

Douglas
Douglas

Reputation: 54877

What you’re doing in your example is called “busy-waiting” (or “spinning”), which is unrecommended in most scenarios since it wastes a lot of CPU power. Preferably, you should use a signalling mechanism, such as the WaitHandle class, for synchronizing when an event of interest (in your case, StatusChangedEvent) has occurred:

public class MSRDevice
{
    StatusInfo _status;
    IPAD _ipad; // <-- the device

    private EventWaitHandle waitHandle = new AutoResetEvent(false);

    public MSRDevice()
    {
        //Initialize device, wire up events, etc.
    }

    public StatusInfo GetStatus()
    {
        _ipad.GetStatus() // <- raises StatusChangedEvent asynchronously
        waitHandle.WaitOne(); // <- waits for signal
        return _status;
    }

    void StateChangedEvent(object sender, DeviceStateChangeEventArgs e) 
    {
        _status = e.StatusInfo;
        waitHandle.Set(); // <- sets signal
    }
}

Upvotes: 5

Marc Gravell
Marc Gravell

Reputation: 1062600

The best option: code it async.

No; that is a hot loop. It will hammer the CPU. It also isn't guaranteed to exit due to register caching (this is trivial to demonstrate on x86 in particular).

If you need it sync, you should use something like an AutoResetEvent.

Upvotes: 2

Related Questions