ReplaySubject.First()意外阻止

时间:2012-11-07 13:14:54

标签: c# .net multithreading system.reactive

我在我正在工作的Silverlight应用程序中遇到了绝对奇怪的行为。请参阅以下代码:

var replaySubject = new ReplaySubject<string>(1);
    replaySubject.OnNext("This can never block... surely?");

var s = replaySubject.First();
Debug.WriteLine(s);

基本上,我的应用程序通过这段代码重复,它总是打印出消息......除了在First()行中线程阻塞的一个特定场景。

它总是在UI线程上。如果我在First()的行上设置了一个断点,并使用调试器钻进replaySubject,我可以在其队列中看到该字符串。

任何人都可以想到会导致First()调用阻止的任何情况吗?

BTW:这是RX版本1.1.11111

2 个答案:

答案 0 :(得分:3)

好的,事实证明,默认情况下,ReplaySubject使用Scheduler.CurrentThread

如果我明确将ReplaySubject设置为使用Scheduler.ImmediateScheduler.ThreadPool,那么它会按预期工作。

var replaySubject = new ReplaySubject<string>(1, Scheduler.Immediate);
    replaySubject.OnNext("This can never block... surely?");

var s = replaySubject.First();
Debug.WriteLine(s);

我仍然需要调查在我的特定场景中UI线程是如何陷入这种混乱的,但是现在,这解决了这个问题。

---编辑---

好的,经过进一步调查,结果发现大部分时间的上述代码都是在ThreadPool线程上启动的。即使它到达代码时,它位于Dispatcher线程上,Scheduler.CurrentThread将ReplaySubject放回原始的ThreadPool线程。

但是,在它破坏的情况下,一切都从用户点击按钮开始。这显然是在UI线程上,当它到达这段代码时,Scheduler.CurrentThread现在是UI线程,因为我们已经在UI线程上,所以我们有一个死锁。首先是等待ReplaySubject泵送 - 但泵在当前操作后面排队等候。微妙的,需要注意的事情。

答案 1 :(得分:0)

从您的代码中可以看出,Observable上没有注册订阅者。因此它可能会等待一个人订阅,因此它可以为您提供第一个可用的。

您可以尝试FirstOrDefault来查看它是否为空。