2012-11-07 65 views
2

我在工作的Silverlight應用程序中遇到了一種絕對的離奇行爲。請看下面的代碼:ReplaySubject.First()意外阻止

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

+1

@Profrofo EGY - 感謝您將代碼關鍵字放入代碼塊中。 但是,我不知道爲什麼你應該將「我」改寫成「我是」 - 是否有一些使用收縮的政策? 另外,我是英語,所以行爲在這裏拼寫爲「U」。希望你不介意。 –

+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線程得到自己進入這個爛攤子我在特定的場景,但現在,這解決了問題。

---編輯---

OK,在進一步的調查,事實證明,大部分的時間上面這段代碼是在一個線程池線程啓動。儘管當它到達代碼時,它在Dispatcher線程上,Scheduler.CurrentThread將ReplaySubject放回到原始的ThreadPool線程上。

但是,在突破的情況下,所有內容都以用戶單擊按鈕開始。這顯然是在UI線程上,當它到達這段代碼時,Scheduler.CurrentThread現在是UI線程,並且由於我們已經在UI線程上,所以我們有一個死鎖。首先是等待ReplaySubject抽水 - 但是泵在當前動作的後面排隊。微妙的東西,要注意。

0

從你的代碼似乎沒有對這個Observable註冊用戶。所以它可能會等待訂閱,所以它可以給你第一個可用。

您可以嘗試FirstOrDefault來查看它是否爲空。

+0

感謝René的迴應。 AFAIK First()設置訂閱,取1,然後關閉訂閱。另外,如果你所說的是真的,那麼上面的代碼總是會阻塞 - 而不是我所看到的是它反覆工作,然後突然阻塞。 –