Silverlight 同期処理
Posted in Silverlight on 10月 16th, 2010 by Site AdministratorSilverlightではWebClient等を使用して、非同期で各種データの取得ができます。
なんとか同期でデータの取得ができないかと調べてみたのですが、結論としては無理っぽい。
下記サンプルはデータを非同期で作成して、作成完了を待って戻すメソッドgetStringを含むtestクラスです。
呼び出し元からすると、getStringは同期処理で動くはずです。
class test { private BackgroundWorker worker = new BackgroundWorker(); private AutoResetEvent are = new AutoResetEvent(false); private string data = ""; public test() { worker.DoWork += new DoWorkEventHandler(worker_DoWork); worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); } public string getString() { data = ""; worker.RunWorkerAsync(); are.WaitOne(); return data; } private void worker_DoWork(object sender, DoWorkEventArgs e) { System.Threading.Thread.Sleep(1000); return; } private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { data = "complete"; are.Set(); } }
上記クラスの呼び出し元について、下記のように書いてみます。
private void button_Click(object sender, RoutedEventArgs e) { MessageBox.Show(this.getData()); } private string getData() { string returnStr = ""; test objTest = new test(); returnStr = objTest.getString(); return returnStr; }
結論として、動きません。反応なしです。書き換えてみます。
private string getData() { string returnStr = ""; Thread newThread = new Thread(() => { test objTest = new test(); returnStr = objTest.getString(); //Dispatcher.BeginInvoke(() => MessageBox.Show(returnStr)); }); newThread.Start(); return returnStr; }
動きますが、メッセージが空白表示です。Dispatcher.BeginInvokeのコメントをはずすと、きちんと表示されます。
別スレッド内では正常に動いているようです。スレッド終了を待つように書き換えてみます。
private string getData() { string returnStr = ""; Thread newThread = new Thread(() => { test objTest = new test(); returnStr = objTest.getString(); // Dispatcher.BeginInvoke(() => MessageBox.Show(returnStr)); }); newThread.Start(); newThread.Join(); return returnStr; }
正常に別スレッドのデータを取得できました!
次に、WebRequestでデータを取得するように変更します。
test.getStringを書き換えます。
public string getString() { data = ""; var wait = new AutoResetEvent(false); WebResponse ret = null; WebRequest wr = WebRequest.Create(new Uri("http://localhost:49698")); wr.BeginGetResponse(gr => { ret = wr.EndGetResponse(gr); wait.Set(); }, null); wait.WaitOne(); var sr = new StreamReader(ret.GetResponseStream(), Encoding.UTF8); data = sr.ReadToEnd(); ret.Close(); return data; }
反応がありません。
getDataのThread.Joinをコメントアウトしてみます。
private string getData() { string returnStr = ""; Thread newThread = new Thread(() => { test objTest = new test(); returnStr = objTest.getString(); // Dispatcher.BeginInvoke(() => MessageBox.Show(returnStr)); }); newThread.Start(); //newThread.Join(); return returnStr; }
動きますが、メッセージが空白表示です。Dispatcher.BeginInvokeのコメントをはずすと、きちんと表示されます。
調べてみると、WebRequestの非同期データ取得の完了イベントは、UIスレッドに通知されるようです。
なので、UIスレッドでJoinなどの停止処理をいれていると、そこでロックがかかってしまうみたいです。
reactive extensionsを使えばできそうでもあるので、今後調べてみます。