使用流的请求/响应

时间:2016-08-09 07:40:32

标签: c# functional-programming system.reactive

我有一个来自RS-232端口的输入流和一个使用Rx流到串口的命令队列。我简化了我的代码如下:

void Init()
{
    SerialPort srl;

    ... // open serial port

    IObservable<string> obInput =
        Observable.FromEventPattern<
        SerialDataReceivedEventHandler,
        SerialDataReceivedEventArgs>
        (
            handler => srl.DataReceived += handler,
            handler => srl.DataReceived -= handler
        ).SelectMany(_ =>
        {
        List<string> ret;
        ... //extract messages
        return ret;
        }).Publish().Refcount();

    obCommandOk =
        obInput
        .Where(msg => msg == "OK" || msg == "KO");

    var sAction = new Subject<string>();
    var sCommandOk = new Subject<Tuple<string,bool>>();

    sAction
        .Do(srl.WriteLine)
        .Zip(obCommandOk, (cmd, result) =>
        {
        if (result == "OK")
            sCommandOk.OnNext(Tuple.Create(cmd, true))
        else
            sCommandOk.OnNext(Tuple.Create(cmd, false))
        });
}

async bool Command(string cmd)
{
    sAction.OnNext(cmd);

    return
        await sCommandOk
        .Where(t => t.Item1 == cmd)
        .Select(t => t.Item2)
        .FirstAsync();
}

有时会发生在OnNext之后,结果已经被推送到sCommandOk,所以我失去了它。

你能否建议我采取更好的方法来避免失去回应?

1 个答案:

答案 0 :(得分:0)

您的Command方法中存在竞争条件。 你推动Action,然后订阅结果。 如果结果很快,那么你就松开了。

这里的一个小改动可以缓解这一点:

async Task<bool> Command(string cmd)
{
    var result = sCommandOk
        .Where(t => t.Item1 == cmd)
        .Select(t => t.Item2)
        .FirstAsync();

    sAction.OnNext(cmd);

    return await result;
}

我认为您可以通过一起删除sCommandOk主题来进一步优化

async Task<bool> Command(string cmd)
{
    var result = obInput
        .Where(t => t.Item1 == cmd)
        .Select(t => t.Item2)
        .FirstAsync();

    sAction.OnNext(cmd);

    return await result;
}