동기 메서드를 비동기 방식으로 호출
.NET에서는 모든 메서드를 비동기 방식으로 호출할 수 있습니다. 해당 작업을 수행하려면 호출하려는 메서드와 동일한 시그니처를 사용하여 대리자를 정의합니다. 공용 언어 런타임은 적절한 시그니처를 사용하여 이 대리자에 대한 BeginInvoke
및 EndInvoke
메서드를 자동으로 정의합니다.
참고 항목
특히 BeginInvoke
및 EndInvoke
메서드와 같은 비동기 대리자는 .NET Compact Framework에서 호출할 수 없습니다.
BeginInvoke
메서드는 비동기 호출을 시작합니다. 이 메서드의 매개 변수는 비동기 방식으로 실행하려는 메서드의 매개 변수와 같으며 두 개의 선택적인 매개 변수가 추가로 사용됩니다. 첫 번째 매개 변수는 비동기 호출이 완료될 때 호출될 메서드를 참조하는 AsyncCallback 대리자이고 두 번째 매개 변수는 콜백 메서드에 정보를 전달하는 사용자 정의 개체입니다. BeginInvoke
는 비동기 호출이 완료되기를 기다리지 않고 즉시 반환합니다. BeginInvoke
는 비동기 호출의 진행률을 모니터링하는 데 사용할 수 있는 IAsyncResult를 반환합니다.
EndInvoke
메서드는 비동기 호출의 결과를 검색합니다. 이 메서드는 BeginInvoke
를 호출한 후 언제든지 호출할 수 있습니다. 비동기 호출이 완료되지 않은 경우 EndInvoke
는 호출이 완료될 때까지 호출하는 스레드를 차단합니다. EndInvoke
의 매개 변수에는 비동기 방식으로 실행하려는 메서드의 out
및 ref
매개 변수(Visual Basic의 경우 <Out>
ByRef
및 ByRef
)와 BeginInvoke
에서 반환하는 IAsyncResult가 포함됩니다.
참고 항목
Visual Studio의 IntelliSense 기능은 BeginInvoke
및 EndInvoke
의 매개 변수를 표시합니다. Visual Studio 또는 이와 유사한 도구를 사용하지 않거나 Visual Studio와 C#을 함께 사용하는 경우 이러한 메서드에 대해 정의된 매개 변수 설명을 보려면 APM(비동기 프로그래밍 모델)을 참조하세요.
이 항목의 코드 예제에서는 BeginInvoke
및 EndInvoke
를 사용하여 비동기 호출을 수행하는 네 가지 일반적인 방법을 보여 줍니다. BeginInvoke
를 호출한 후 다음과 같은 작업을 수행할 수 있습니다.
작업을 수행한 다음
EndInvoke
를 호출하여 호출이 완료될 때까지 실행을 차단합니다.IAsyncResult.AsyncWaitHandle 속성을 사용하여 WaitHandle을 가져오고 해당 WaitOne 메서드를 사용하여 WaitHandle이 신호를 받을 때까지 실행을 차단한 다음,
EndInvoke
를 호출합니다.IAsyncResult 에서 반환한
BeginInvoke
를 폴링하여 비동기 호출이 완료되는 시점을 확인한 다음EndInvoke
를 호출합니다.콜백 메서드의 대리자를
BeginInvoke
에 전달합니다. 이 메서드는 비동기 호출이 완료될 때 ThreadPool 스레드에서 실행됩니다. 콜백 메서드는EndInvoke
를 호출합니다.
Important
사용하는 방법에 관계없이 항상 EndInvoke
를 호출하여 비동기 호출을 완료해야 합니다.
테스트 메서드 및 비동기 대리자 정의
다음 코드 예제에서는 동일한 장기 실행 메서드인 TestMethod
를 비동기 방식으로 호출하는 다양한 방법을 보여 줍니다. TestMethod
메서드는 처리를 시작했음을 나타내는 콘솔 메시지를 표시하고 몇 초간 대기한 후 종료됩니다. TestMethod
에는 out
및 BeginInvoke
의 시그니처에 해당 매개 변수가 추가되는 방식을 보여 주는 EndInvoke
매개 변수가 있습니다. ref
매개 변수도 마찬가지로 처리할 수 있습니다.
다음 코드 예제에서는 TestMethod
의 정의와 AsyncMethodCaller
를 비동기식으로 호출하는 데 사용할 수 있는 TestMethod
라는 대리자를 보여 줍니다. 코드 예제를 컴파일하려면 TestMethod
및 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
EndInvoke로 비동기 호출 대기
메서드를 비동기 방식으로 실행하는 가장 간단한 방법은 대리자의 BeginInvoke
메서드를 호출하여 메서드 실행을 시작하고 주 스레드에서 작업을 수행한 다음 대리자의 EndInvoke
메서드를 호출하는 것입니다. EndInvoke
는 비동기 호출이 완료될 때까지 반환되지 않으므로 호출하는 스레드를 차단할 수도 있습니다. 이 방법은 파일 또는 네트워크 작업에 적합합니다.
Important
EndInvoke
는 실행을 차단할 수 있으므로 사용자 인터페이스를 제공하는 스레드에서는 호출하지 말아야 합니다.
#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 AsyncMain
{
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 {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(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.".
WaitHandle로 비동기 호출 대기
WaitHandle 에서 반환하는 AsyncWaitHandle 의 IAsyncResult 속성을 사용하여 BeginInvoke
을 가져올 수 있습니다. 비동기 호출이 완료되면 WaitHandle 은 신호를 받으며 WaitOne 메서드를 호출하여 대기할 수 있습니다.
WaitHandle을 사용하는 경우 비동기 호출이 완료되기 전이나 후에 추가 작업을 처리한 다음 EndInvoke
를 호출하여 결과를 검색할 수 있습니다.
참고 항목
대기 핸들은 EndInvoke
를 호출할 때 자동으로 닫히지 않습니다. 대기 핸들에 대한 모든 참조를 해제하면 가비지 수집에서 대기 핸들을 회수할 때 시스템 리소스가 확보됩니다. 대기 핸들 사용을 마친 후 시스템 리소스를 즉시 확보하려면 WaitHandle.Close 메서드를 호출하여 핸들을 삭제합니다. 삭제 가능한 개체를 명시적으로 삭제하면 가비지 컬렉션의 효율성이 향상됩니다.
#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 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);
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(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.".
비동기 호출 완료에 대한 폴링
IsCompleted 에서 반환하는 IAsyncResult 의 BeginInvoke
속성을 사용하여 비동기 호출이 완료되는 시점을 확인할 수 있습니다. 사용자 인터페이스를 제공하는 스레드에서 비동기 호출을 수행하는 경우 이 동작을 수행할 수 있습니다. 완료에 대해 폴링하면 비동기 호출이 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.".
비동기 호출이 완료될 때 콜백 메서드 실행
비동기 호출을 시작하는 스레드와 결과를 처리하는 스레드가 서로 다를 수 있는 경우에는 호출이 완료될 때 콜백 메서드를 실행할 수 있습니다. 콜백 메서드는 ThreadPool 스레드에서 실행됩니다.
콜백 메서드를 사용하려면 BeginInvoke
에 콜백 메서드를 나타내는 AsyncCallback 대리자를 전달해야 합니다. 콜백 메서드에서 사용할 정보가 들어 있는 개체를 전달할 수도 있습니다. 콜백 메서드에서는 콜백 메서드의 유일한 매개 변수인 IAsyncResult를 AsyncResult 개체로 캐스팅할 수 있습니다. 그런 다음 AsyncResult.AsyncDelegate 속성을 사용하여 호출을 시작하는 데 사용된 대리자를 가져오면 EndInvoke
를 호출할 수 있습니다.
예제 관련 참고 사항:
TestMethod
의threadId
매개 변수는out
매개 변수(Visual Basic의 경우 [<Out>
ByRef
)이므로 입력 값은TestMethod
에서 사용되지 않습니다.BeginInvoke
를 호출할 때는 더미 변수가 전달됩니다.threadId
매개 변수가ref
매개 변수(Visual Basic의 경우ByRef
)인 경우에는 변수가BeginInvoke
및EndInvoke
에 전달 가능한 클래스 수준 필드여야 합니다.BeginInvoke
에 전달되는 상태 정보는 콜백 메서드에서 출력 메시지의 형식을 지정하는 데 사용하는 형식 문자열입니다. 이 문자열은 Object형식으로 전달되므로 상태 정보를 적절한 형식으로 캐스팅해야 사용할 수 있습니다.콜백은 ThreadPool 스레드에서 수행됩니다. ThreadPool 스레드는 주 스레드가 종료된 경우 애플리케이션 실행을 유지하지 않는 배경 스레드이므로 예제의 주 스레드는 콜백이 완료될 때까지 충분히 대기해야 합니다.
#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 AsyncMain
{
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 {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.");
}
// 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.
참고 항목
.NET