将同步包装器置于异步方法之上

本文关键字:异步方法 同步 包装 | 更新日期: 2023-09-27 18:25:10

我正在与一个带有包含异步方法的api的PIN设备集成。例如,其中一个被称为GetStatus,它引发DeviceStateChangedEvent,并将状态作为参数传递给它。

不过,我希望有一个不是异步的接口,这样当我在接口上调用GetStatus时,它实际上会返回状态,而不是引发一个事件来将数据传递给我。

我想我可以做这样的事情:

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;
    }
}

这是解决这个问题的好方法吗?还是有更好的解决方案?

将同步包装器置于异步方法之上

您在示例中所做的被称为"忙等待"(或"旋转"),这在大多数情况下是不被注意的,因为它浪费了大量的CPU功率。最好,您应该使用一种信号机制,如WaitHandle类,用于在感兴趣的事件(在您的情况下为StatusChangedEvent)发生时进行同步:

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
    }
}

最好的选择:异步编码。

否;这是一个热循环。它将冲击CPU。由于寄存器缓存,它也不能保证退出(特别是在x86上演示这一点很琐碎)。

如果您需要它同步,您应该使用类似AutoResetEvent的东西。