スレッドプール側で投げる例外に注意
http://d.hatena.ne.jp/akiramei/20060124/p1
↑は、ちょっと説明が足りなすぎなので補足します。
using System; using System.Threading; delegate void SilverSkin (); class Program { static void Lance () { throw new Exception ("届け…"); } static void Callback (IAsyncResult r) { SilverSkin ss = r.AsyncState as SilverSkin; Console.WriteLine ("In Callback."); try { ss.EndInvoke (r); } catch (Exception) { Console.WriteLine ("例外をそのまま投げる."); throw; } } static void Main () { // 1.Threadの場合は例外が発生する Thread t = new Thread (new ThreadStart (Lance)); t.IsBackground = true; t.Start (); Console.WriteLine ("スレッドで発生した例外はUnhandled."); Thread.Sleep (1000); // 2.Delegate.BeginInvokeはEndInvokeを呼ばないと // 例外がスレッドプールに食われる SilverSkin ss = new SilverSkin (Lance); IAsyncResult r = ss.BeginInvoke (null, null); r.AsyncWaitHandle.WaitOne (); Console.WriteLine ("BeginInvokeだけならUnhandledにならない."); Thread.Sleep (1000); // 3.Delegate.EndInvokeを呼ぶと、例外が受けられる r = ss.BeginInvoke (null, null); r.AsyncWaitHandle.WaitOne (); try { ss.EndInvoke (r); } catch (Exception e) { Console.WriteLine ("EndInvoke from Main."); } Console.WriteLine ("EndInvokeを呼ぶと例外が飛ぶ."); Thread.Sleep (1000); // 4. Callback内の例外はスレッドプールに食われる r = ss.BeginInvoke (new AsyncCallback (Callback), null); r.AsyncWaitHandle.WaitOne (); Console.WriteLine ("Callback内で例外が発生してもUnhandledにならない."); Thread.Sleep (1000); } } /* 結果 Unhandled Exception: System.Exception: 届け… in <0x00024> Program:Lance () in (wrapper delegate-invoke) System.MulticastDelegate:invoke_void () スレッドで発生した例外はUnhandled. BeginInvokeだけならUnhandledにならない. EndInvoke from Main. EndInvokeを呼ぶと例外が飛ぶ. In Callback. 例外をそのまま投げる. Callback内で例外が発生してもUnhandledにならない. */
- 通常のスレッドで例外が発生すれば、どこにもキャッチされない
- BeginInvokeを呼びっぱなしの場合、例外は闇に葬られます
- EndInvokeでスレッドから投げられた例外が飛ばされます
- Callbackはスレッドプール側なので、例外は闇に葬られます
例に出していませんがTimerイベントで飛ばした例外もスレッドプール側なので同じ運命です。