Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Platforma .NET umożliwia asynchroniczne wywoływanie dowolnej metody. Aby to zrobić, musisz zdefiniować delegata z takim samym podpisem, jakiego potrzebuje metoda, którą chcesz wywołać. Środowisko uruchomieniowe języka ogólnego automatycznie definiuje metody BeginInvoke
i EndInvoke
dla tego delegata z odpowiednimi sygnaturami.
Uwaga
Asynchroniczne wywołania delegatów, w szczególności metody BeginInvoke
oraz EndInvoke
, nie są obsługiwane w ramach .NET Compact Framework.
Metoda BeginInvoke
inicjuje wywołanie asynchroniczne. Ma te same parametry co metoda, którą chcesz wykonać asynchronicznie, oraz dwa dodatkowe parametry opcjonalne. Pierwszy parametr to AsyncCallback delegat, który odwołuje się do metody, która ma być wywoływana po zakończeniu wywołania asynchronicznego. Drugi parametr to obiekt zdefiniowany przez użytkownika, który przekazuje informacje do metody wywołania zwrotnego.
BeginInvoke
zwraca natychmiast i nie oczekuje na zakończenie wywołania asynchronicznego.
BeginInvoke
Zwraca obiekt IAsyncResult, który może służyć do monitorowania postępu wywołania asynchronicznego.
Metoda EndInvoke
służy do pobierania wyników wywołania asynchronicznego. Można go wywołać w dowolnym momencie po BeginInvoke
. Jeśli wywołanie asynchroniczne nie zostało ukończone, EndInvoke
blokuje wątek wywołujący do momentu jego zakończenia. Parametry EndInvoke
funkcji zawierają parametry out
i ref
(<Out>
ByRef
i ByRef
w Visual Basic) metody, którą chcesz wykonać asynchronicznie, oraz IAsyncResult zwrócone przez metodę BeginInvoke
.
Uwaga
Funkcja IntelliSense w programie Visual Studio wyświetla parametry parametrów BeginInvoke
i EndInvoke
. Jeśli nie używasz programu Visual Studio lub podobnego narzędzia lub jeśli używasz języka C# w programie Visual Studio, zobacz Asynchronous Programming Model (APM), aby uzyskać opis parametrów zdefiniowanych dla tych metod.
Przykłady kodu w tym temacie demonstrują cztery typowe sposoby używania BeginInvoke
i EndInvoke
do wykonywania wywołań asynchronicznych. Po wywołaniu połączenia BeginInvoke
można wykonać następujące czynności:
Wykonaj pewną pracę, a następnie zadzwoń
EndInvoke
, aby zablokować, dopóki połączenie nie zostanie zakończone.WaitHandle uzyskaj przy użyciu właściwości IAsyncResult.AsyncWaitHandle, użyj jego metody WaitOne, aby zablokować wykonanie, dopóki WaitHandle nie zostanie zasygnalizowany, a następnie wywołaj metodę
EndInvoke
.Sonduj obiekt zwrócony przez
BeginInvoke
w celu ustalenia, kiedy wywołanie asynchroniczne zostało ukończone, a następnie wywołajEndInvoke
.Przekaż delegata do metody wywołania zwrotnego
BeginInvoke
. Po zakończeniu wywołania asynchronicznego metoda jest wykonywana na wątku ThreadPool. Metoda wywołania zwrotnego wywołujeEndInvoke
.
Ważne
Niezależnie od używanej techniki, zawsze wywołaj metodę EndInvoke
, aby ukończyć wywołanie asynchroniczne.
Definiowanie metody testowej i delegata asynchronicznego
Poniższe przykłady kodu przedstawiają różne sposoby wywoływania tej samej długotrwałej metody , TestMethod
asynchronicznie. Metoda TestMethod
wyświetla komunikat na konsoli, aby pokazać, że rozpoczęto przetwarzanie, następnie zawiesza działanie na kilka sekund i kończy działanie.
TestMethod
out
ma parametr w celu pokazania, jak takie parametry są dodawane do sygnatur elementów BeginInvoke
i EndInvoke
. Możesz obsługiwać parametry ref
podobnie.
Poniższy przykład kodu przedstawia definicję TestMethod
i delegata o nazwie AsyncMethodCaller
, który może służyć do wywoływania TestMethod
asynchronicznego. Aby skompilować przykłady kodu, należy uwzględnić definicje dla TestMethod
i delegata AsyncMethodCaller
.
using namespace System;
using namespace System::Threading;
using namespace System::Runtime::InteropServices;
namespace Examples {
namespace AdvancedProgramming {
namespace AsynchronousOperations
{
public ref class AsyncDemo
{
public:
// The method to be executed asynchronously.
String^ TestMethod(int callDuration, [OutAttribute] int% threadId)
{
Console::WriteLine("Test method begins.");
Thread::Sleep(callDuration);
threadId = Thread::CurrentThread->ManagedThreadId;
return String::Format("My call time was {0}.", callDuration);
}
};
// The delegate must have the same signature as the method
// it will call asynchronously.
public delegate String^ AsyncMethodCaller(int callDuration, [OutAttribute] int% threadId);
}}}
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncDemo
{
// The method to be executed asynchronously.
public string TestMethod(int callDuration, out int threadId)
{
Console.WriteLine("Test method begins.");
Thread.Sleep(callDuration);
threadId = Thread.CurrentThread.ManagedThreadId;
return String.Format("My call time was {0}.", callDuration.ToString());
}
}
// The delegate must have the same signature as the method
// it will call asynchronously.
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncDemo
' The method to be executed asynchronously.
Public Function TestMethod(ByVal callDuration As Integer, _
<Out> ByRef threadId As Integer) As String
Console.WriteLine("Test method begins.")
Thread.Sleep(callDuration)
threadId = Thread.CurrentThread.ManagedThreadId()
return String.Format("My call time was {0}.", callDuration.ToString())
End Function
End Class
' The delegate must have the same signature as the method
' it will call asynchronously.
Public Delegate Function AsyncMethodCaller(ByVal callDuration As Integer, _
<Out> ByRef threadId As Integer) As String
End Namespace
Oczekiwanie na asynchroniczne wywołanie za pomocą funkcji EndInvoke
Najprostszym sposobem wykonania metody asynchronicznej jest rozpoczęcie wykonywania metody przez wywołanie metody delegata BeginInvoke
, wykonanie pewnych czynności w wątku głównym, a następnie wywołanie metody delegata EndInvoke
.
EndInvoke
może zablokować wątek wywołujący, ponieważ nie jest zwracany do momentu zakończenia wywołania asynchronicznego. Jest to dobra technika do użycia z operacjami plików lub sieci.
Ważne
Z uwagi na to, że EndInvoke
może blokować, nigdy nie należy go wywoływać z wątków obsługujących interfejs użytkownika.
#using <TestMethod.dll>
using namespace System;
using namespace System::Threading;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;
void main()
{
// The asynchronous method puts the thread id here.
int threadId = 2546;
// Create an instance of the test class.
AsyncDemo^ ad = gcnew AsyncDemo();
// Create the delegate.
AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
// Initiate the asynchronous call.
IAsyncResult^ result = caller->BeginInvoke(3000,
threadId, nullptr, nullptr);
Thread::Sleep(1);
Console::WriteLine("Main thread {0} does some work.",
Thread::CurrentThread->ManagedThreadId);
// Call EndInvoke to wait for the asynchronous call to complete,
// and to retrieve the results.
String^ returnValue = caller->EndInvoke(threadId, result);
Console::WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
/* This example produces output similar to the following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain3
{
public static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asynchronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine($"Main thread {Thread.CurrentThread.ManagedThreadId} does some work.");
// Call EndInvoke to wait for the asynchronous call to complete,
// and to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' Initiate the asynchronous call.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
threadId, Nothing, Nothing)
Thread.Sleep(0)
Console.WriteLine("Main thread {0} does some work.", _
Thread.CurrentThread.ManagedThreadId)
' Call EndInvoke to Wait for the asynchronous call to complete,
' and to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, result)
Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
'This example produces output similar to the following:
'
'Main thread 1 does some work.
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
Oczekiwanie na asynchroniczne wywołanie z waitHandle
Można uzyskać WaitHandle za pomocą właściwości AsyncWaitHandle, zwracanej przez BeginInvoke
, obiektu IAsyncResult. Element WaitHandle jest sygnalizowany po zakończeniu wywołania asynchronicznego, a następnie możesz poczekać, wywołując metodę WaitOne.
Jeśli używasz WaitHandle, możesz wykonać dodatkowe przetwarzanie przed lub po zakończeniu wywołania asynchronicznego, ale przed wywołaniem EndInvoke
w celu pobrania wyników.
Uwaga
Uchwyt oczekiwania nie jest zamykany automatycznie przy wywołaniu EndInvoke
. Jeśli zwolnisz wszystkie odwołania do uchwytu oczekiwania, zasoby systemowe zostaną uwolnione, gdy mechanizm garbage collection odzyska uchwyt oczekiwania. Aby zwolnić zasoby systemowe zaraz po zakończeniu korzystania z uchwytu oczekiwania, należy go zlikwidować, wywołując metodę WaitHandle.Close. Odzyskiwanie pamięci działa wydajniej, gdy obiekty jednorazowe są jawnie usuwane.
#using <TestMethod.dll>
using namespace System;
using namespace System::Threading;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;
void main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo^ ad = gcnew AsyncDemo();
// Create the delegate.
AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
// Initiate the asynchronous call.
IAsyncResult^ result = caller->BeginInvoke(3000,
threadId, nullptr, nullptr);
Thread::Sleep(0);
Console::WriteLine("Main thread {0} does some work.",
Thread::CurrentThread->ManagedThreadId);
// Wait for the WaitHandle to become signaled.
result->AsyncWaitHandle->WaitOne();
// Perform additional processing here.
// Call EndInvoke to retrieve the results.
String^ returnValue = caller->EndInvoke(threadId, result);
// Close the wait handle.
result->AsyncWaitHandle->Close();
Console::WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
/* This example produces output similar to the following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain2
{
static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asynchronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine($"Main thread {Thread.CurrentThread.ManagedThreadId} does some work.");
// Wait for the WaitHandle to become signaled.
result.AsyncWaitHandle.WaitOne();
// Perform additional processing here.
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
// Close the wait handle.
result.AsyncWaitHandle.Close();
Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
Main thread 1 does some work.
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
*/
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' Initiate the asynchronous call.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
threadId, Nothing, Nothing)
Thread.Sleep(0)
Console.WriteLine("Main thread {0} does some work.", _
Thread.CurrentThread.ManagedThreadId)
' Perform additional processing here and then
' wait for the WaitHandle to be signaled.
result.AsyncWaitHandle.WaitOne()
' Call EndInvoke to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, result)
' Close the wait handle.
result.AsyncWaitHandle.Close()
Console.WriteLine("The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
'This example produces output similar to the following:
'
'Main thread 1 does some work.
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
Monitorowanie zakończenia wywołań asynchronicznych
Możesz użyć właściwości IsCompleted obiektu IAsyncResult, zwróconego przez BeginInvoke
, aby stwierdzić, kiedy wywołanie asynchroniczne zostanie zakończone. Można to zrobić podczas wykonywania wywołania asynchronicznego z wątku, który obsługuje interfejs użytkownika. Odpytywanie w celu zakończenia umożliwia wątkowi wywołującemu kontynuowanie działania, podczas gdy wywołanie asynchroniczne jest wykonywane w wątku ThreadPool.
#using <TestMethod.dll>
using namespace System;
using namespace System::Threading;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;
void main()
{
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo^ ad = gcnew AsyncDemo();
// Create the delegate.
AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
// Initiate the asynchronous call.
IAsyncResult^ result = caller->BeginInvoke(3000,
threadId, nullptr, nullptr);
// Poll while simulating work.
while(result->IsCompleted == false)
{
Thread::Sleep(250);
Console::Write(".");
}
// Call EndInvoke to retrieve the results.
String^ returnValue = caller->EndInvoke(threadId, result);
Console::WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
/* This example produces output similar to the following:
Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
*/
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main() {
// The asynchronous method puts the thread id here.
int threadId;
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// Initiate the asynchronous call.
IAsyncResult result = caller.BeginInvoke(3000,
out threadId, null, null);
// Poll while simulating work.
while(result.IsCompleted == false) {
Thread.Sleep(250);
Console.Write(".");
}
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, result);
Console.WriteLine("\nThe call executed on thread {0}, with return value \"{1}\".",
threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
Test method begins.
.............
The call executed on thread 3, with return value "My call time was 3000.".
*/
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' Initiate the asynchronous call.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
threadId, Nothing, Nothing)
' Poll while simulating work.
While result.IsCompleted = False
Thread.Sleep(250)
Console.Write(".")
End While
' Call EndInvoke to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, result)
Console.WriteLine(vbCrLf & _
"The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
' This example produces output similar to the following:
'
'Test method begins.
'.............
'The call executed on thread 3, with return value "My call time was 3000.".
Wykonywanie metody wywołania zwrotnego po zakończeniu wywołania asynchronicznego
Jeśli wątek, który inicjuje wywołanie asynchroniczne, nie musi być wątkiem, który przetwarza wyniki, można wykonać metodę wywołania zwrotnego po zakończeniu wywołania. Metoda wywołania zwrotnego jest wykonywana w wątku ThreadPool .
Aby użyć metody wywołania zwrotnego, należy przekazać BeginInvoke
AsyncCallback delegata reprezentującego metodę wywołania zwrotnego. Można również przekazać obiekt zawierający informacje, które mają być używane przez metodę wywołania zwrotnego. W metodzie wywołania zwrotnego można rzutować IAsyncResult , który jest jedynym parametrem metody wywołania zwrotnego, na obiekt AsyncResult. Następnie możesz użyć AsyncResult.AsyncDelegate właściwości , aby uzyskać delegata, który został użyty do zainicjowania wywołania, aby można było wywołać metodę EndInvoke
.
Uwagi dotyczące przykładu:
Parametr
threadId
to parametrTestMethod
out
([<Out>
ByRef
w Visual Basic), więc jego wartość wejściowa nigdy nie jest wykorzystywana przezTestMethod
. Fikcyjna zmienna jest przekazywana do wywołaniaBeginInvoke
.threadId
Gdyby parametr był parametremref
(ByRef
w Visual Basic), zmienna musiałaby być polem na poziomie klasy, aby można było go przekazać zarówno doBeginInvoke
jak i doEndInvoke
.Informacje o stanie przekazane do
BeginInvoke
to łańcuch formatowania, którego metoda wywołania zwrotnego używa do formatowania komunikatu wyjściowego. Ponieważ jest on przekazywany jako typ Object, informacje o stanie muszą być rzutowane do odpowiedniego typu, zanim będzie można go użyć.Wywołanie zwrotne jest wykonywane w wątku ThreadPool. ThreadPool wątki to wątki w tle, które nie utrzymują działania aplikacji, gdy główny wątek się zakończy, więc główny wątek przykładu musi być wstrzymany na wystarczająco długo, aby wywołanie zwrotne się zakończyło.
#using <TestMethod.dll>
using namespace System;
using namespace System::Threading;
using namespace System::Runtime::Remoting::Messaging;
using namespace Examples::AdvancedProgramming::AsynchronousOperations;
// The callback method must have the same signature as the
// AsyncCallback delegate.
void CallbackMethod(IAsyncResult^ ar)
{
// Retrieve the delegate.
AsyncResult^ result = (AsyncResult^) ar;
AsyncMethodCaller^ caller = (AsyncMethodCaller^) result->AsyncDelegate;
// Retrieve the format string that was passed as state
// information.
String^ formatString = (String^) ar->AsyncState;
// Define a variable to receive the value of the out parameter.
// If the parameter were ref rather than out then it would have to
// be a class-level field so it could also be passed to BeginInvoke.
int threadId = 0;
// Call EndInvoke to retrieve the results.
String^ returnValue = caller->EndInvoke(threadId, ar);
// Use the format string to format the output message.
Console::WriteLine(formatString, threadId, returnValue);
};
void main()
{
// Create an instance of the test class.
AsyncDemo^ ad = gcnew AsyncDemo();
// Create the delegate.
AsyncMethodCaller^ caller = gcnew AsyncMethodCaller(ad, &AsyncDemo::TestMethod);
// The threadId parameter of TestMethod is an out parameter, so
// its input value is never used by TestMethod. Therefore, a dummy
// variable can be passed to the BeginInvoke call. If the threadId
// parameter were a ref parameter, it would have to be a class-
// level field so that it could be passed to both BeginInvoke and
// EndInvoke.
int dummy = 0;
// Initiate the asynchronous call, passing three seconds (3000 ms)
// for the callDuration parameter of TestMethod; a dummy variable
// for the out parameter (threadId); the callback delegate; and
// state information that can be retrieved by the callback method.
// In this case, the state information is a string that can be used
// to format a console message.
IAsyncResult^ result = caller->BeginInvoke(3000,
dummy,
gcnew AsyncCallback(&CallbackMethod),
"The call executed on thread {0}, with return value \"{1}\".");
Console::WriteLine("The main thread {0} continues to execute...",
Thread::CurrentThread->ManagedThreadId);
// The callback is made on a ThreadPool thread. ThreadPool threads
// are background threads, which do not keep the application running
// if the main thread ends. Comment out the next line to demonstrate
// this.
Thread::Sleep(4000);
Console::WriteLine("The main thread ends.");
}
/* This example produces output similar to the following:
The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
*/
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain4
{
static void Main()
{
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
// Create the delegate.
AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
// The threadId parameter of TestMethod is an out parameter, so
// its input value is never used by TestMethod. Therefore, a dummy
// variable can be passed to the BeginInvoke call. If the threadId
// parameter were a ref parameter, it would have to be a class-
// level field so that it could be passed to both BeginInvoke and
// EndInvoke.
int dummy = 0;
// Initiate the asynchronous call, passing three seconds (3000 ms)
// for the callDuration parameter of TestMethod; a dummy variable
// for the out parameter (threadId); the callback delegate; and
// state information that can be retrieved by the callback method.
// In this case, the state information is a string that can be used
// to format a console message.
IAsyncResult result = caller.BeginInvoke(3000,
out dummy,
new AsyncCallback(CallbackMethod),
"The call executed on thread {0}, with return value \"{1}\".");
Console.WriteLine($"The main thread {Thread.CurrentThread.ManagedThreadId} continues to execute...");
// The callback is made on a ThreadPool thread. ThreadPool threads
// are background threads, which do not keep the application running
// if the main thread ends. Comment out the next line to demonstrate
// this.
Thread.Sleep(4000);
Console.WriteLine("The main thread ends.");
}
// The callback method must have the same signature as the
// AsyncCallback delegate.
static void CallbackMethod(IAsyncResult ar)
{
// Retrieve the delegate.
AsyncResult result = (AsyncResult) ar;
AsyncMethodCaller caller = (AsyncMethodCaller) result.AsyncDelegate;
// Retrieve the format string that was passed as state
// information.
string formatString = (string) ar.AsyncState;
// Define a variable to receive the value of the out parameter.
// If the parameter were ref rather than out then it would have to
// be a class-level field so it could also be passed to BeginInvoke.
int threadId = 0;
// Call EndInvoke to retrieve the results.
string returnValue = caller.EndInvoke(out threadId, ar);
// Use the format string to format the output message.
Console.WriteLine(formatString, threadId, returnValue);
}
}
}
/* This example produces output similar to the following:
The main thread 1 continues to execute...
Test method begins.
The call executed on thread 3, with return value "My call time was 3000.".
The main thread ends.
*/
Imports System.Threading
Imports System.Runtime.Remoting.Messaging
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' Create an instance of the test class.
Dim ad As New AsyncDemo()
' Create the delegate.
Dim caller As New AsyncMethodCaller(AddressOf ad.TestMethod)
' The threadId parameter of TestMethod is an <Out> parameter, so
' its input value is never used by TestMethod. Therefore, a dummy
' variable can be passed to the BeginInvoke call. If the threadId
' parameter were a ByRef parameter, it would have to be a class-
' level field so that it could be passed to both BeginInvoke and
' EndInvoke.
Dim dummy As Integer = 0
' Initiate the asynchronous call, passing three seconds (3000 ms)
' for the callDuration parameter of TestMethod; a dummy variable
' for the <Out> parameter (threadId); the callback delegate; and
' state information that can be retrieved by the callback method.
' In this case, the state information is a string that can be used
' to format a console message.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
dummy, _
AddressOf CallbackMethod, _
"The call executed on thread {0}, with return value ""{1}"".")
Console.WriteLine("The main thread {0} continues to execute...", _
Thread.CurrentThread.ManagedThreadId)
' The callback is made on a ThreadPool thread. ThreadPool threads
' are background threads, which do not keep the application running
' if the main thread ends. Comment out the next line to demonstrate
' this.
Thread.Sleep(4000)
Console.WriteLine("The main thread ends.")
End Sub
' The callback method must have the same signature as the
' AsyncCallback delegate.
Shared Sub CallbackMethod(ByVal ar As IAsyncResult)
' Retrieve the delegate.
Dim result As AsyncResult = CType(ar, AsyncResult)
Dim caller As AsyncMethodCaller = CType(result.AsyncDelegate, AsyncMethodCaller)
' Retrieve the format string that was passed as state
' information.
Dim formatString As String = CType(ar.AsyncState, String)
' Define a variable to receive the value of the <Out> parameter.
' If the parameter were ByRef rather than <Out> then it would have to
' be a class-level field so it could also be passed to BeginInvoke.
Dim threadId As Integer = 0
' Call EndInvoke to retrieve the results.
Dim returnValue As String = caller.EndInvoke(threadId, ar)
' Use the format string to format the output message.
Console.WriteLine(formatString, threadId, returnValue)
End Sub
End Class
End Namespace
' This example produces output similar to the following:
'
'The main thread 1 continues to execute...
'Test method begins.
'The call executed on thread 3, with return value "My call time was 3000.".
'The main thread ends.