私のメソッドの1つ(Method1
)が新しいスレッドを生成します。そのスレッドはメソッド(Method2
)を実行し、実行中に例外がスローされます。呼び出しメソッドに関する例外情報を取得する必要があります(Method1
)
Method1
スローされるので、この例外をキャッチできるのMethod2
ですか?
私のメソッドの1つ(Method1
)が新しいスレッドを生成します。そのスレッドはメソッド(Method2
)を実行し、実行中に例外がスローされます。呼び出しメソッドに関する例外情報を取得する必要があります(Method1
)
Method1
スローされるので、この例外をキャッチできるのMethod2
ですか?
回答:
では、.NET 4と上記の、あなたが使用することができTask<T>
、新しいスレッドを作成するのではなく、クラスを。次に.Exceptions
、タスクオブジェクトのプロパティを使用して例外を取得できます。それには2つの方法があります。
別のメソッドで://一部のタスクのスレッドで例外を処理します
class Program
{
static void Main(string[] args)
{
Task<int> task = new Task<int>(Test);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
Console.ReadLine();
}
static int Test()
{
throw new Exception();
}
static void ExceptionHandler(Task<int> task)
{
var exception = task.Exception;
Console.WriteLine(exception);
}
}
同じメソッドで:// 呼び出し元のスレッドで例外を処理します
class Program
{
static void Main(string[] args)
{
Task<int> task = new Task<int>(Test);
task.Start();
try
{
task.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
static int Test()
{
throw new Exception();
}
}
あなたが得る例外はであることに注意してくださいAggregateException
。すべての実際の例外は、ex.InnerExceptions
プロパティを通じて利用できます。
では.NET 3.5は、次のコードを使用することができます。
// 子のスレッドで例外を処理します
class Program
{
static void Main(string[] args)
{
Exception exception = null;
Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler));
thread.Start();
Console.ReadLine();
}
private static void Handler(Exception exception)
{
Console.WriteLine(exception);
}
private static void SafeExecute(Action test, Action<Exception> handler)
{
try
{
test.Invoke();
}
catch (Exception ex)
{
Handler(ex);
}
}
static void Test(int a, int b)
{
throw new Exception();
}
}
または// 呼び出し元のスレッドで例外を処理します
class Program
{
static void Main(string[] args)
{
Exception exception = null;
Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception));
thread.Start();
thread.Join();
Console.WriteLine(exception);
Console.ReadLine();
}
private static void SafeExecute(Action test, out Exception exception)
{
exception = null;
try
{
test.Invoke();
}
catch (Exception ex)
{
exception = ex;
}
}
static void Test(int a, int b)
{
throw new Exception();
}
}
Test
。のような() => Test(myParameter1, myParameter2)
Method1では例外をキャッチできません。ただし、Method2で例外をキャッチして、実行の元のスレッドが読み取って操作できる変数に記録することができます。
異なるスレッド間でデータを共有する最も簡単な方法はshared data
次のとおりです(一部は擬似コードです)。
class MyThread
{
public string SharedData;
public void Worker()
{
...lengthy action, infinite loop, etc...
SharedData = "whatever";
...lengthy action...
return;
}
}
class Program
{
static void Main()
{
MyThread m = new MyThread();
Thread WorkerThread = new Thread(m.Worker);
WorkerThread.Start();
loop//or e.g. a Timer thread
{
f(m.SharedData);
}
return;
}
}
この方法については、マルチスレッディングに関するこの素晴らしい紹介で読むことができますがO'Reilly book C# 3.0 in a nutshell
、これについては、新しいバージョンの本と同じように、Googleブックスでも自由にアクセスできるAlbahari兄弟(2007)ので読むことをお勧めします。スレッドプーリング、フォアグラウンドスレッドとバックグラウンドスレッドなどもカバーしているため、わかりやすくシンプルなサンプルコードを使用しています。(免責事項:私はこの本の古くなったコピーを所有しています)
WinFormsアプリケーションを作成している場合、WinFormコントロールはスレッドセーフではないため、共有データの使用は特に便利です。コールバックを使用してワーカースレッドからWinFormコントロールにデータを戻すには、Invoke()
そのコントロールをスレッドセーフにするためにメインUIスレッドに醜いコードが必要です。代わりに共有データとシングルスレッドSystem.Windows.Forms.Timer
を使用すると、Interval
たとえば0.2秒と短いため、ワーカースレッドからコントロールに簡単に情報を送信できますInvoke
。
統合テストスイートからのコントロールを含むアイテムを使用したいので、STAスレッドを作成する必要があるという特定の問題がありました。私が最終的に作成したコードは次のとおりです。他の人が同じ問題を抱えている場合に備えて、ここに配置してください。
public Boolean? Dance(String name) {
// Already on an STA thread, so just go for it
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA) return DanceSTA(name);
// Local variable to hold the caught exception until the caller can rethrow
Exception lException = null;
Boolean? lResult = null;
// A gate to hold the calling thread until the called thread is done
var lGate = new ManualResetEvent(false);
var lThreadStart = new ThreadStart(() => {
try {
lResult = DanceSTA(name);
} catch (Exception ex) {
lException = ex;
}
lGate.Set();
});
var lThread = new Thread(lThreadStart);
lThread.SetApartmentState(ApartmentState.STA);
lThread.Start();
lGate.WaitOne();
if (lException != null) throw lException;
return lResult;
}
public Boolean? DanceSTA(String name) { ... }
これは、コードをそのまま貼り付けたものです。他の用途については、アクションまたは関数をパラメーターとして指定し、呼び出されたメソッドをハードコーディングする代わりに、スレッドで呼び出すことをお勧めします。