Threads maken en gegevens doorgeven bij de start
Wanneer een besturingssysteemproces wordt gemaakt, injecteert het besturingssysteem een thread om code in dat proces uit te voeren, inclusief elk oorspronkelijk toepassingsdomein. Vanaf dat moment kunnen toepassingsdomeinen worden gemaakt en vernietigd zonder dat eventuele besturingssysteemthreads noodzakelijkerwijs worden gemaakt of vernietigd. Als de code die wordt uitgevoerd beheerde code is, kan een Thread object voor de thread die wordt uitgevoerd in het huidige toepassingsdomein worden verkregen door de eigenschap statische CurrentThread van het type Threadop te halen. In dit onderwerp wordt het maken van threads beschreven en worden alternatieven besproken voor het doorgeven van gegevens aan de threadprocedure.
Een thread maken
Als u een nieuw Thread-object maakt, wordt er een nieuwe beheerde thread gemaakt. De Thread-klasse heeft constructors die een ThreadStart gedelegeerde of een ParameterizedThreadStart gedelegeerde nemen; de gedelegeerde verpakt de methode die wordt aangeroepen door de nieuwe thread wanneer u de Start methode aanroept. Als Start meer dan één keer wordt aangeroepen, wordt er een ThreadStateException gegenereerd.
De Start-methode retourneert onmiddellijk, vaak voordat de nieuwe thread daadwerkelijk is gestart. U kunt de eigenschappen ThreadState en IsAlive gebruiken om de status van de thread op elk moment te bepalen, maar deze eigenschappen mogen nooit worden gebruikt voor het synchroniseren van de activiteiten van threads.
Notitie
Zodra een thread is gestart, is het niet nodig om een verwijzing naar het Thread-object te behouden. De thread wordt nog steeds uitgevoerd totdat de threadprocedure eindigt.
In het volgende codevoorbeeld worden twee nieuwe threads gemaakt voor het aanroepen van exemplaren en statische methoden voor een ander object.
using namespace System;
using namespace System::Threading;
public ref class ServerClass
{
public:
// The method that will be called when the thread is started.
void InstanceMethod()
{
Console::WriteLine(
"ServerClass.InstanceMethod is running on another thread.");
// Pause for a moment to provide a delay to make
// threads more apparent.
Thread::Sleep(3000);
Console::WriteLine(
"The instance method called by the worker thread has ended.");
}
static void StaticMethod()
{
Console::WriteLine(
"ServerClass.StaticMethod is running on another thread.");
// Pause for a moment to provide a delay to make
// threads more apparent.
Thread::Sleep(5000);
Console::WriteLine(
"The static method called by the worker thread has ended.");
}
};
public ref class Simple
{
public:
static void Main()
{
ServerClass^ serverObject = gcnew ServerClass();
// Create the thread object, passing in the
// serverObject.InstanceMethod method using a
// ThreadStart delegate.
Thread^ InstanceCaller = gcnew Thread(
gcnew ThreadStart(serverObject, &ServerClass::InstanceMethod));
// Start the thread.
InstanceCaller->Start();
Console::WriteLine("The Main() thread calls this after "
+ "starting the new InstanceCaller thread.");
// Create the thread object, passing in the
// serverObject.StaticMethod method using a
// ThreadStart delegate.
Thread^ StaticCaller = gcnew Thread(
gcnew ThreadStart(&ServerClass::StaticMethod));
// Start the thread.
StaticCaller->Start();
Console::WriteLine("The Main() thread calls this after "
+ "starting the new StaticCaller thread.");
}
};
int main()
{
Simple::Main();
}
// The example displays output like the following:
// The Main() thread calls this after starting the new InstanceCaller thread.
// The Main() thread calls this after starting the new StaticCaller thread.
// ServerClass.StaticMethod is running on another thread.
// ServerClass.InstanceMethod is running on another thread.
// The instance method called by the worker thread has ended.
// The static method called by the worker thread has ended.
using System;
using System.Threading;
public class ServerClass
{
// The method that will be called when the thread is started.
public void InstanceMethod()
{
Console.WriteLine(
"ServerClass.InstanceMethod is running on another thread.");
// Pause for a moment to provide a delay to make
// threads more apparent.
Thread.Sleep(3000);
Console.WriteLine(
"The instance method called by the worker thread has ended.");
}
public static void StaticMethod()
{
Console.WriteLine(
"ServerClass.StaticMethod is running on another thread.");
// Pause for a moment to provide a delay to make
// threads more apparent.
Thread.Sleep(5000);
Console.WriteLine(
"The static method called by the worker thread has ended.");
}
}
public class Simple
{
public static void Main()
{
ServerClass serverObject = new ServerClass();
// Create the thread object, passing in the
// serverObject.InstanceMethod method using a
// ThreadStart delegate.
Thread InstanceCaller = new(new ThreadStart(serverObject.InstanceMethod));
// Start the thread.
InstanceCaller.Start();
Console.WriteLine("The Main() thread calls this after "
+ "starting the new InstanceCaller thread.");
// Create the thread object, passing in the
// serverObject.StaticMethod method using a
// ThreadStart delegate.
Thread StaticCaller = new(new ThreadStart(ServerClass.StaticMethod));
// Start the thread.
StaticCaller.Start();
Console.WriteLine("The Main() thread calls this after "
+ "starting the new StaticCaller thread.");
}
}
// The example displays the output like the following:
// The Main() thread calls this after starting the new InstanceCaller thread.
// The Main() thread calls this after starting the new StaticCaller thread.
// ServerClass.StaticMethod is running on another thread.
// ServerClass.InstanceMethod is running on another thread.
// The instance method called by the worker thread has ended.
// The static method called by the worker thread has ended.
Imports System.Threading
Public class ServerClass
' The method that will be called when the thread is started.
Public Sub InstanceMethod()
Console.WriteLine(
"ServerClass.InstanceMethod is running on another thread.")
' Pause for a moment to provide a delay to make
' threads more apparent.
Thread.Sleep(3000)
Console.WriteLine(
"The instance method called by the worker thread has ended.")
End Sub
Public Shared Sub SharedMethod()
Console.WriteLine(
"ServerClass.SharedMethod is running on another thread.")
' Pause for a moment to provide a delay to make
' threads more apparent.
Thread.Sleep(5000)
Console.WriteLine(
"The Shared method called by the worker thread has ended.")
End Sub
End Class
Public class Simple
Public Shared Sub Main()
Dim serverObject As New ServerClass()
' Create the thread object, passing in the
' serverObject.InstanceMethod method using a
' ThreadStart delegate.
Dim InstanceCaller As New Thread(AddressOf serverObject.InstanceMethod)
' Start the thread.
InstanceCaller.Start()
Console.WriteLine("The Main() thread calls this after " _
+ "starting the new InstanceCaller thread.")
' Create the thread object, passing in the
' serverObject.SharedMethod method using a
' ThreadStart delegate.
Dim SharedCaller As New Thread( _
New ThreadStart(AddressOf ServerClass.SharedMethod))
' Start the thread.
SharedCaller.Start()
Console.WriteLine("The Main() thread calls this after " _
+ "starting the new SharedCaller thread.")
End Sub
End Class
' The example displays output like the following:
' The Main() thread calls this after starting the new InstanceCaller thread.
' The Main() thread calls this after starting the new StaticCaller thread.
' ServerClass.StaticMethod is running on another thread.
' ServerClass.InstanceMethod is running on another thread.
' The instance method called by the worker thread has ended.
' The static method called by the worker thread has ended.
Gegevens doorgeven aan threads
De ParameterizedThreadStart gedelegeerde biedt een eenvoudige manier om een object met gegevens door te geven aan een thread wanneer u Thread.Start(Object)aanroept. Zie ParameterizedThreadStart voor een codevoorbeeld.
Het gebruik van de ParameterizedThreadStart gedelegeerde is geen typeveilige manier om gegevens door te geven, omdat de methode Thread.Start(Object) elk object accepteert. U kunt ook de threadprocedure en de gegevens in een helperklasse inkapselen en de ThreadStart gemachtigde gebruiken om de threadprocedure uit te voeren. In het volgende voorbeeld ziet u deze techniek:
using namespace System;
using namespace System::Threading;
// The ThreadWithState class contains the information needed for
// a task, and the method that executes the task.
//
public ref class ThreadWithState
{
private:
// State information used in the task.
String^ boilerplate;
int numberValue;
// The constructor obtains the state information.
public:
ThreadWithState(String^ text, int number)
{
boilerplate = text;
numberValue = number;
}
// The thread procedure performs the task, such as formatting
// and printing a document.
void ThreadProc()
{
Console::WriteLine(boilerplate, numberValue);
}
};
// Entry point for the example.
//
public ref class Example
{
public:
static void Main()
{
// Supply the state information required by the task.
ThreadWithState^ tws = gcnew ThreadWithState(
"This report displays the number {0}.", 42);
// Create a thread to execute the task, and then
// start the thread.
Thread^ t = gcnew Thread(gcnew ThreadStart(tws, &ThreadWithState::ThreadProc));
t->Start();
Console::WriteLine("Main thread does some work, then waits.");
t->Join();
Console::WriteLine(
"Independent task has completed; main thread ends.");
}
};
int main()
{
Example::Main();
}
// This example displays the following output:
// Main thread does some work, then waits.
// This report displays the number 42.
// Independent task has completed; main thread ends.
using System;
using System.Threading;
// The ThreadWithState class contains the information needed for
// a task, and the method that executes the task.
//
public class ThreadWithState
{
// State information used in the task.
private string _boilerplate;
private int _numberValue;
// The constructor obtains the state information.
public ThreadWithState(string text, int number)
{
_boilerplate = text;
_numberValue = number;
}
// The thread procedure performs the task, such as formatting
// and printing a document.
public void ThreadProc()
{
Console.WriteLine(_boilerplate, _numberValue);
}
}
// Entry point for the example.
public class Example
{
public static void Main()
{
// Supply the state information required by the task.
ThreadWithState tws = new("This report displays the number {0}.", 42);
// Create a thread to execute the task, and then
// start the thread.
Thread t = new(new ThreadStart(tws.ThreadProc));
t.Start();
Console.WriteLine("Main thread does some work, then waits.");
t.Join();
Console.WriteLine(
"Independent task has completed; main thread ends.");
}
}
// The example displays the following output:
// Main thread does some work, then waits.
// This report displays the number 42.
// Independent task has completed; main thread ends.
Imports System.Threading
' The ThreadWithState class contains the information needed for
' a task, and the method that executes the task.
Public Class ThreadWithState
' State information used in the task.
Private boilerplate As String
Private numberValue As Integer
' The constructor obtains the state information.
Public Sub New(text As String, number As Integer)
boilerplate = text
numberValue = number
End Sub
' The thread procedure performs the task, such as formatting
' and printing a document.
Public Sub ThreadProc()
Console.WriteLine(boilerplate, numberValue)
End Sub
End Class
' Entry point for the example.
'
Public Class Example
Public Shared Sub Main()
' Supply the state information required by the task.
Dim tws As New ThreadWithState( _
"This report displays the number {0}.", 42)
' Create a thread to execute the task, and then
' start the thread.
Dim t As New Thread(New ThreadStart(AddressOf tws.ThreadProc))
t.Start()
Console.WriteLine("Main thread does some work, then waits.")
t.Join()
Console.WriteLine( _
"Independent task has completed main thread ends.")
End Sub
End Class
' The example displays the following output:
' Main thread does some work, then waits.
' This report displays the number 42.
' Independent task has completed; main thread ends.
Noch ThreadStart noch ParameterizedThreadStart gedelegeerde heeft een retourwaarde, omdat er geen mogelijkheid is om de gegevens van een asynchrone aanroep terug te geven. Als u de resultaten van een threadmethode wilt ophalen, kunt u een callback-methode gebruiken, zoals wordt weergegeven in de volgende sectie.
Gegevens ophalen uit threads met callback-methoden
In het volgende voorbeeld ziet u een callback-methode waarmee gegevens uit een thread worden opgehaald. De constructor voor de klasse die de gegevens bevat en de threadmethode accepteert ook een gemachtigde die de callback-methode vertegenwoordigt; voordat de threadmethode wordt beëindigd, wordt de callback-gemachtigde aangeroepen.
using namespace System;
using namespace System::Threading;
// Delegate that defines the signature for the callback method.
//
public delegate void ExampleCallback(int lineCount);
// The ThreadWithState class contains the information needed for
// a task, the method that executes the task, and a delegate
// to call when the task is complete.
//
public ref class ThreadWithState
{
private:
// State information used in the task.
String^ boilerplate;
int numberValue;
// Delegate used to execute the callback method when the
// task is complete.
ExampleCallback^ callback;
public:
// The constructor obtains the state information and the
// callback delegate.
ThreadWithState(String^ text, int number,
ExampleCallback^ callbackDelegate)
{
boilerplate = text;
numberValue = number;
callback = callbackDelegate;
}
// The thread procedure performs the task, such as
// formatting and printing a document, and then invokes
// the callback delegate with the number of lines printed.
void ThreadProc()
{
Console::WriteLine(boilerplate, numberValue);
if (callback != nullptr)
{
callback(1);
}
}
};
// Entry point for the example.
//
public ref class Example
{
public:
static void Main()
{
// Supply the state information required by the task.
ThreadWithState^ tws = gcnew ThreadWithState(
"This report displays the number {0}.",
42,
gcnew ExampleCallback(&Example::ResultCallback)
);
Thread^ t = gcnew Thread(gcnew ThreadStart(tws, &ThreadWithState::ThreadProc));
t->Start();
Console::WriteLine("Main thread does some work, then waits.");
t->Join();
Console::WriteLine(
"Independent task has completed; main thread ends.");
}
// The callback method must match the signature of the
// callback delegate.
//
static void ResultCallback(int lineCount)
{
Console::WriteLine(
"Independent task printed {0} lines.", lineCount);
}
};
int main()
{
Example::Main();
}
// The example displays the following output:
// Main thread does some work, then waits.
// This report displays the number 42.
// Independent task printed 1 lines.
// Independent task has completed; main thread ends.
using System;
using System.Threading;
// The ThreadWithState2 class contains the information needed for
// a task, the method that executes the task, and a delegate
// to call when the task is complete.
public class ThreadWithState2
{
// State information used in the task.
private string _boilerplate;
private int _numberValue;
// Delegate used to execute the callback method when the
// task is complete.
private ExampleCallback _callback;
// The constructor obtains the state information and the
// callback delegate.
public ThreadWithState2(string text, int number,
ExampleCallback callbackDelegate)
{
_boilerplate = text;
_numberValue = number;
_callback = callbackDelegate;
}
// The thread procedure performs the task, such as
// formatting and printing a document, and then invokes
// the callback delegate with the number of lines printed.
public void ThreadProc()
{
Console.WriteLine(_boilerplate, _numberValue);
_callback?.Invoke(1);
}
}
// Delegate that defines the signature for the callback method.
public delegate void ExampleCallback(int lineCount);
// Entry point for the example.
public class Example2
{
public static void Main()
{
// Supply the state information required by the task.
ThreadWithState2 tws = new(
"This report displays the number {0}.",
42,
new ExampleCallback(ResultCallback)
);
Thread t = new(new ThreadStart(tws.ThreadProc));
t.Start();
Console.WriteLine("Main thread does some work, then waits.");
t.Join();
Console.WriteLine(
"Independent task has completed; main thread ends.");
}
// The callback method must match the signature of the
// callback delegate.
public static void ResultCallback(int lineCount)
{
Console.WriteLine($"Independent task printed {lineCount} lines.");
}
}
// The example displays the following output:
// Main thread does some work, then waits.
// This report displays the number 42.
// Independent task printed 1 lines.
// Independent task has completed; main thread ends.
Imports System.Threading
' The ThreadWithState class contains the information needed for
' a task, the method that executes the task, and a delegate
' to call when the task is complete.
Public Class ThreadWithState
' State information used in the task.
Private boilerplate As String
Private numberValue As Integer
' Delegate used to execute the callback method when the
' task is complete.
Private callback As ExampleCallback
' The constructor obtains the state information and the
' callback delegate.
Public Sub New(text As String, number As Integer, _
callbackDelegate As ExampleCallback)
boilerplate = text
numberValue = number
callback = callbackDelegate
End Sub
' The thread procedure performs the task, such as
' formatting and printing a document, and then invokes
' the callback delegate with the number of lines printed.
Public Sub ThreadProc()
Console.WriteLine(boilerplate, numberValue)
If Not (callback Is Nothing) Then
callback(1)
End If
End Sub
End Class
' Delegate that defines the signature for the callback method.
'
Public Delegate Sub ExampleCallback(lineCount As Integer)
Public Class Example
Public Shared Sub Main()
' Supply the state information required by the task.
Dim tws As New ThreadWithState( _
"This report displays the number {0}.", _
42, _
AddressOf ResultCallback)
Dim t As New Thread(AddressOf tws.ThreadProc)
t.Start()
Console.WriteLine("Main thread does some work, then waits.")
t.Join()
Console.WriteLine( _
"Independent task has completed; main thread ends.")
End Sub
Public Shared Sub ResultCallback(lineCount As Integer)
Console.WriteLine( _
"Independent task printed {0} lines.", lineCount)
End Sub
End Class
' The example displays the following output:
' Main thread does some work, then waits.
' This report displays the number 42.
' Independent task printed 1 lines.
' Independent task has completed; main thread ends.