C++ Win32 응용프로그램의 동작 방식을 보면 Loop를 돌면서 메시지를 처리하는 방식이다. 이 메시지들 중에 화면을 그리는 메시지, 동작에 관련된 메시지, 종료 메시지 등이 존재한다. 그래서 이 Thread 루틴에 다른 Thread에서 어떤 메시지를 전달하고 싶을 때는 SendMessage()나 PostMessage()를 통해 전달하게 된다. 이 둘의 차이점은 동기 방식이냐 비동기 방식이냐이다. 즉, SendMessage()로 메시지를 전달하면 해당 메시지가 Loop Thread에서 처리되기 전까지는 반환되지 않는다. 그로 인해 호출한 Thread는 Holding이 된다. 그리고 만약 Loop Thread가 그 메시지를 처리하는 과정에서 자원을 필요로 하는 자원을 호출한 Thread가 쥐고 있다면 Deadlock이 되어 버린다. 이와 반대로 PostMessage()는 어떤 동작에 대한 메시지를 Message Queue에다 넣고 바로 반환해 버린다. 그럼 Loop Thread가 Message Queue에 있는 메시지를 처리하게 되므로 위와 같은 문제가 발생하지 않는다.
C#의 Invoke와 BeginInvoke도 이와 비슷한 개념이다. C#에서 화면을 그리는 Thread는 하나만 존재한다. 다른 Thread에서 화면을 그리기 위해 해당 자원을 바로 접근해 버리면 이상동작을 할 수 있으므로 이를 방지하기 위한 설계이다. 따라서 다른 Thread는 화면 처리와 관련해서는 화면을 그리는 Thread로 Message를 전달해야 한다. 이 때, 사용될 수 있는 것이 Invoke()과 BeginInvoke()이다. 이들은 처리해야 되는 루틴을 delegate로 만들고 필요한 인자를 같이 전달받아 처리한다. Invoke()는 C++의 SendMessage()와 마찬가지로 동기방식이고 BeginInvoke()는 PostMessage()와 마찬가지로 비동기 방식이다. 일반적으로 BeginInvoke()를 사용하면 된다. Invoke()는 동기방식이기 때문에 꼭 반환결과가 필요한 경우에 사용하는 것이 좋다.
아래는 delegate에서 화면을 그리는 Thread로 요청을 보내는 코드이다.
public void RdsHandler(IntPtr pCBContext, ref RDS_CBEvet evt) { if( evt.evtCode == 224) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("PI {0} Group type {1} PTY {2} \n" , evt.groupInfo.pi, evt.groupInfo.groupType, evt.groupInfo.pty); if (_closing == false) { if (this.rdsOutPutText.InvokeRequired) { SetTextCallback d = new SetTextCallback(RdsHandler); this.BeginInvoke(d, new object[] { pCBContext, evt }); } else { this.rdsOutPutText.Text += sb.ToString(); } } } }