2016-08-09 49 views
0

我有一个来自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

我们能否旨在提供http://stackoverflow.com请/帮助/麦克风?当然,我知道它是伪代码,但它与编译的真正的C#大约有5个变化。 –

+0

@LeeCampbell推断你从我的代码中请求的内容是相当困难的,但我写了一些东西在这里编译https://gist.github.com/zpul/b7a59e559e523a8a3b1077b1ec8013ef(对于SO来说太大) – zpul

+0

你真的不应该使用来自'SelectMany'的外部可变缓冲区,这真是一个非常糟糕的主意。你将能够保证对其内容完全没有任何影响。 – TheInnerLight

回答

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

不幸的是,我已经尝试过这种方法,问题依然存在。我现在发现的唯一解决方案是与命令一起传递一个结果变量,如果在设置了OnNext之后,我已经有了结果,否则我将等待。这是一个非常糟糕的,所以我不喜欢它。 – zpul