我有一个来自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,所以我失去了它。
你能否建议我采取更好的方法来避免失去回应?
答案 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;
}