マルチスレッド プロシージャのパラメーターと戻り値 (C# および Visual Basic)
スレッド クラスのコンストラクターは、引数を取らず値を返さないプロシージャに参照を渡す必要があるため、マルチスレッド アプリケーションでの値の受け渡しは複雑です。 以下のセクションでは、異なるスレッドのプロシージャからパラメーターを指定して値を返す単純な方法を示します。
マルチスレッド プロシージャのパラメーターの指定
マルチスレッド メソッドの呼び出しにパラメーターを指定する最良の方法は、クラスにターゲット メソッドをラップし、新規スレッドのパラメーターとして機能するフィールドをそのクラスに対して定義することです。 この方法の利点は、新規スレッドを開始するたびに独自のパラメーターでクラスの新規インスタンスを作成できることです。 たとえば、次のコードに示すように三角形の面積を計算する関数があるとします。
Function CalcArea(ByVal Base As Double, ByVal Height As Double) As Double
CalcArea = 0.5 * Base * Height
End Function
double CalcArea(double Base, double Height)
{
return 0.5 * Base * Height;
}
CalcArea 関数をラップして入力パラメーターを格納するフィールドを作成するクラスを記述するコードは次のとおりです。
Class AreaClass
Public Base As Double
Public Height As Double
Public Area As Double
Sub CalcArea()
Area = 0.5 * Base * Height
MessageBox.Show("The area is: " & Area.ToString)
End Sub
End Class
class AreaClass
{
public double Base;
public double Height;
public double Area;
public void CalcArea()
{
Area = 0.5 * Base * Height;
MessageBox.Show("The area is: " + Area.ToString());
}
}
AreaClass を使用するには、次のコードに示すように AreaClass オブジェクトを作成し、Base プロパティと Height プロパティを設定します。
Protected Sub TestArea()
Dim AreaObject As New AreaClass
Dim Thread As New System.Threading.Thread(
AddressOf AreaObject.CalcArea)
AreaObject.Base = 30
AreaObject.Height = 40
Thread.Start()
End Sub
protected void TestArea()
{
AreaClass AreaObject = new AreaClass();
System.Threading.Thread Thread =
new System.Threading.Thread(AreaObject.CalcArea);
AreaObject.Base = 30;
AreaObject.Height = 40;
Thread.Start();
}
TestArea プロシージャは CalcArea メソッドの呼び出し後に Area フィールドの値を確認しないことに注意してください。 CalcArea は別のスレッドで実行されるため、Thread.Start を呼び出した直後に確認する場合は、Area フィールドが設定されているとは限りません。 次のセクションでは、マルチスレッド プロシージャから値を返す適切な方法について説明します。
マルチスレッド プロシージャからの戻り値
異なるスレッドで実行されるプロシージャの場合、値を返す動作は複雑になります。プロシージャは関数にすることができず、ByRef 引数を使用できないからです。 値を返す最も簡単な方法は、BackgroundWorker コンポーネントを使ってスレッドを管理し、タスクが完了したときにイベントを生成し、結果をイベント ハンドラーで処理することです。
次の例では、別のスレッドで実行中のプロシージャからイベントを発生させて値を返します。
Private Class AreaClass2
Public Base As Double
Public Height As Double
Function CalcArea() As Double
' Calculate the area of a triangle.
Return 0.5 * Base * Height
End Function
End Class
Private WithEvents BackgroundWorker1 As New System.ComponentModel.BackgroundWorker
Private Sub TestArea2()
Dim AreaObject2 As New AreaClass2
AreaObject2.Base = 30
AreaObject2.Height = 40
' Start the asynchronous operation.
BackgroundWorker1.RunWorkerAsync(AreaObject2)
End Sub
' This method runs on the background thread when it starts.
Private Sub BackgroundWorker1_DoWork(
ByVal sender As Object,
ByVal e As System.ComponentModel.DoWorkEventArgs
) Handles BackgroundWorker1.DoWork
Dim AreaObject2 As AreaClass2 = CType(e.Argument, AreaClass2)
' Return the value through the Result property.
e.Result = AreaObject2.CalcArea()
End Sub
' This method runs on the main thread when the background thread finishes.
Private Sub BackgroundWorker1_RunWorkerCompleted(
ByVal sender As Object,
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs
) Handles BackgroundWorker1.RunWorkerCompleted
' Access the result through the Result property.
Dim Area As Double = CDbl(e.Result)
MessageBox.Show("The area is: " & Area.ToString)
End Sub
class AreaClass2
{
public double Base;
public double Height;
public double CalcArea()
{
// Calculate the area of a triangle.
return 0.5 * Base * Height;
}
}
private System.ComponentModel.BackgroundWorker BackgroundWorker1
= new System.ComponentModel.BackgroundWorker();
private void TestArea2()
{
InitializeBackgroundWorker();
AreaClass2 AreaObject2 = new AreaClass2();
AreaObject2.Base = 30;
AreaObject2.Height = 40;
// Start the asynchronous operation.
BackgroundWorker1.RunWorkerAsync(AreaObject2);
}
private void InitializeBackgroundWorker()
{
// Attach event handlers to the BackgroundWorker object.
BackgroundWorker1.DoWork +=
new System.ComponentModel.DoWorkEventHandler(BackgroundWorker1_DoWork);
BackgroundWorker1.RunWorkerCompleted +=
new System.ComponentModel.RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);
}
private void BackgroundWorker1_DoWork(
object sender,
System.ComponentModel.DoWorkEventArgs e)
{
AreaClass2 AreaObject2 = (AreaClass2)e.Argument;
// Return the value through the Result property.
e.Result = AreaObject2.CalcArea();
}
private void BackgroundWorker1_RunWorkerCompleted(
object sender,
System.ComponentModel.RunWorkerCompletedEventArgs e)
{
// Access the result through the Result property.
double Area = (double)e.Result;
MessageBox.Show("The area is: " + Area.ToString());
}
スレッド プールのスレッドにパラメーターと戻り値を用意するには、QueueUserWorkItem メソッドの省略可能な状態オブジェクト変数 (ByVal) を使用します。 スレッド タイマーのスレッドもこの目的で状態オブジェクトをサポートしています。 スレッド プールおよびスレッド タイマーの詳細については、「スレッド プール (C# および Visual Basic)」および「スレッド タイマー (C# および Visual Basic)」を参照してください。
参照
処理手順
チュートリアル: BackgroundWorker コンポーネントでのマルチスレッド (C# および Visual Basic)
参照
概念
スレッド プール (C# および Visual Basic)
マルチスレッド アプリケーション (C# および Visual Basic)