Parametri e valori restituiti per routine multithreading (C# e Visual Basic)
L'invio e la restituzione di valori in un'applicazione multithreading è un processo complesso, perché è necessario che il costruttore della classe di thread riceva un riferimento a una routine che non riceve alcun argomento e non restituisce alcun valore. Nelle sezioni seguenti sono indicati alcuni semplici metodi per l'inserimento di parametri e la restituzione di valori da routine su thread diversi.
Inserimento di parametri per routine multithreading
Il modo migliore per inserire i parametri per una chiamata di metodo multithreading consiste nel racchiudere il metodo desiderato in una classe e definire per tale classe dei campi che serviranno da parametri per il nuovo thread. Il vantaggio di questo approccio è dato dalla possibilità di creare una nuova istanza della classe, con parametri propri, ogni volta che si desidera iniziare un nuovo thread. Si supponga, ad esempio, di avere una funzione che calcola l'area di un triangolo, come nel codice che segue:
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;
}
È possibile scrivere una classe che racchiuda la funzione CalcArea e crei i campi in cui memorizzare i parametri di input, come nell'esempio seguente:
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());
}
}
Per utilizzare AreaClass, è possibile creare un oggetto AreaClass e impostare le proprietà Base e Height come mostrato nel codice che segue:
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();
}
Si noti che la routine TestArea non verifica il valore del campo Area dopo che è stato chiamato il metodo CalcArea. Dato che CalcArea viene eseguito su un thread separato, il campo Area non sarà necessariamente impostato se lo si controlla subito dopo avere chiamato Thread.Start. Nella sezione che segue è illustrato un metodo più efficace per la restituzione di valori dalle routine multithreading.
Restituzione di valori da routine multithreading
La restituzione di valori da routine eseguite su thread diversi è complicata dal fatto che le routine non possono essere funzioni e non possono utilizzare argomenti ByRef. Il modo più semplice per eseguire la restituizione di valori consiste nell'utilizzare il componente BackgroundWorker per gestire i thread e generare un evento una volta completata l'attività, quindi elaborare i risultati tramite un gestore eventi.
L'esempio seguente restituisce un valore generando un evento da una routine eseguita su un thread separato:
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());
}
La variabile facoltativa dell'oggetto di stato ByVal del metodo QueueUserWorkItem consente di fornire parametri e restituire valori ai thread del pool di thread. Un oggetto di stato viene supportato a questo scopo anche dai thread dei timer di thread. Per informazioni sul pooling dei thread e i timer di thread, vedere Creazione di pool di thread (C# e Visual Basic) e Timer di thread (C# e Visual Basic).
Vedere anche
Attività
Procedura dettagliata: multithreading con il componente BackgroundWorker (C# e Visual Basic)
Riferimenti
Sincronizzazione di thread (C# e Visual Basic)
Eventi (Guida per programmatori C#)
Delegati (Guida per programmatori C#)
Concetti
Creazione di pool di thread (C# e Visual Basic)
Applicazioni multithreading (C# e Visual Basic)