개요
6. BeginInvoke4(BeginInvoke예제)
이번게시글에서는 비동기작업의 콜백에 대해 알아보겠습니다.
콜백이란 피호출자가 호출자의 메서드를 실행해주는 것을 말하며
BeginInvoke에서의 콜백메서드는 비동기작업이 끝난 직후 실행됩니다.
(보통 비동기작업은 외부에서 끝내주는 경우가 많아 콜백이라고 합니다.)
즉 비동기호출을 한 스레드는 비동기의 일이 진행이 되던 말던 신경을 안쓰고 다음줄을 실행하게 되는데
작업이 끝났다는걸 콜백메서드를 통해 보고받고 원하는 로직을 실행한다고 생각하시면 됩니다.
비동기호출을 한 스레드를 블락시키거나, 스레드를 하나 더 만들어서 변수를 폴링시켜
비슷한 동작을 하게 할 수는 있으나
콜백은 비동기호출을 실행한 스레드가 살아있든, 죽어있든 호출되어
호출한 스레드를 따로 블락시킬 필요가 없으며
비동기호출의 IAsyncResult 및 매개변수를 받아와 작업을 할 수 있는 등 장점이 많습니다.
사용법을 예제코드를 통해 확인해보겠습니다.
1. 예제
namespace BeginInvokeTest3
{
delegate int myDelegate(int n);
class Program
{
static void Main(string[] args)
{
myDelegate a = Func;
int cnt = 10;
Console.WriteLine("1부터 {0}까지 더하고 다 더하면 결과를 말해주세요",cnt);
// 첫번째 매개변수는 비동기작업에 전달하는 매개변수
// 두번째 매개변수는 콜백메서드
// 세번째 매개변수는 콜백메서드에 전달할 object형식의 매개변수이며
// 콜백메서드에서 ar.AsyncState로 받아 올 수 있습니다.
// 지난번 Thread1편의 여러개의 매개변수를 전달하는 방법처럼
// 객체를 넘겨주는 경우가 많습니다.
IAsyncResult ar = a.BeginInvoke(cnt, new AsyncCallback(myCallback),cnt);
Console.WriteLine("더할때까지 기다리고 있겠습니다.");
// 이번게시글에서는 리턴값을 호출한 스레드에서 받아오지않으므로
// WaitOne을 사용해서 메인스레드를 블락시켜줘야합니다.
// 리턴값이 있다면 EndInvoke를 통해 리턴값이 나올때까지 블락시킬수도 있지만
// msdn에서는 리턴값이 있든 없든
// AsyncWaitHandle.WaitOne()을 사용하여 블락시킬것을 권장합니다.
ar.AsyncWaitHandle.WaitOne();
Console.WriteLine("다 더했다면 결과를 알려주세요");
// 콜백메서드가 실행될수 있게 1초를 기다려준후 프로그램이 종료됩니다.
Thread.Sleep(1000);
}
// 비동기 작업이 완료된 후 콜백메서드가 실행됩니다.
private static void myCallback(IAsyncResult ar)
{
// EndInvoke를 사용하면 비동기 구문의 리턴값을 받아올 수 있습니다.
myDelegate temp = ((AsyncResult)ar).AsyncDelegate as myDelegate;
int result = temp.EndInvoke(ar);
Console.WriteLine("1부터 {0}까지의 합은 {1}입니다.", ar.AsyncState, result);
}
private static int Func(int n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += i;
Thread.Sleep(100);
}
Console.WriteLine(sum);
return sum;
}
}
}
저번게시글과 비슷하게 비동기작업으로 1부터 n까지의 합을 구하고 있습니다.
그러나 이번에는 콜백메서드에서 리턴값을 받아오도록 만들었습니다.
메인스레드는 비동기작업을 지시하고 WaitOne에서 작업이 끝날때까지 블락된 후
작업이 끝나면 WaitOne이 싱글상태가 되어 "다 더했다면 결과를 알려주세요"를 출력합니다.
비동기작업 스레드(스레드풀의 스레드)는 비동기작업이 끝나면 콜백메서드에서
결과를 콘솔창에 뿌려주고 있습니다.
2. 주의점
두가지 주의할 점이 있습니다.
1. EndInvoke는 한번만 호출 할 수 있습니다.
콜백메서드에서 리턴값을 받아올지
비동기작업을 호출한 스레드에서 리턴값을 받아올지
한가지를 정해서 로직을 짜야한다는 점에 주의하셔야 됩니다.
양쪽에서 호출하면 컴파일에러가 납니다.
2. "다 더했다면 결과를 알려주세요"가 출력되는 시점을 잘 확인해야 합니다.
해당 문자열의 출력시점은 콜백메서드의 종료가 아닌, 비동기작업의 종료시점입니다.
즉 waitOne에서의 블락이 풀리는 시점은 콜백메서드의 종료가아닌 비동기작업의 끝입니다.
끝.
'c#' 카테고리의 다른 글
[c#] BeginInvoke 사용법 및 예제 -4- (BeginInvoke 예제) (3) | 2020.10.02 |
---|---|
[c#] BeginInvoke사용법 및 예제 -2-(비동기 리턴값) (0) | 2020.09.07 |
[c#] 인터페이스 사용법 및 예제 (0) | 2020.08.03 |
[c#] BeginInvoke사용법 및 예제 -1- (0) | 2020.08.03 |
[c#] lock 사용법 및 예제 (0) | 2020.08.03 |
댓글