Home Full Site
윈도우 멀티쓰레딩

윈도우 프로그래밍에서 멀티쓰레드를 사용하기 위해서는 흔히 Thread 클래스를 이용해 새로운 쓰레드를 만들거나, 쓰레드풀/Task 등을 이용하거나, 혹은 이전에 설명한 BackgroundWorker Wrapper 클래스를 사용한다. 윈도우 멀티쓰레딩에서 중요한 사항은 UI 컨트롤들을 갱신하기 위해서는 항상 해당 UI 컨트롤을 생성한 UI Thread에서 갱신하여야 한다는 것이다. 이를 어기고 다른 Worker Thread가 UI 컨트롤을 엑세스하면 다음과 에러가 발생한다. "Cross-thread operation not valid: Control [progressBar1] accessed from a thread other than the thread it was created on." 아래 예제는 Thread 클래스를 통해 새 쓰레드를 만든 후, 파일 복사를 하면서 진행사항을 ProgressBar에 표시하는 예이다. 이 예제에서는 Worker 쓰레드가 직접 progressBar1 객체를 갱신하려 했기 때문에 에러가 발생했다.

예제

private void btnRun_Click(object sender, EventArgs e)
{
   Thread worker = new Thread(new ThreadStart(MyThreadRun));
   worker.Start();
}

private void MyThreadRun()
{
   string srcDir = @"C:\Temp\_Src";
   string destDir = @"C:\Temp\_Dest";

   DirectoryInfo di = new DirectoryInfo(srcDir);
   FileInfo[] fileInfos = di.GetFiles();
   int totalFiles = fileInfos.Length;
   int counter = 0;
   int pct = 0;
   foreach (var fi in fileInfos)
   {
      string destFile = Path.Combine(destDir, fi.Name);
      File.Copy(fi.FullName, destFile);
      //Thread.Sleep(1000);
      pct = ((++counter * 100) / totalFiles);
      ShowProgress(pct);
   }  
}

private void ShowProgress(int pct)
{
   progressBar1.Value = pct; //<== 에러발생!
}



InvokeRequired 속성

위와 같은 문제점을 해결하기 위해 쓰레드 함수에서 UI 컨트롤을 엑세스할 때, 항상 Control클래스의 InvokeRequired 속성을 체크하여 현재 쓰레드로 컨트롤을 엑세스할 수 있는지를 검사해야 한다. 만약 InvokeRequired값이 true이면, 현재 쓰레드는 Worker Thread라는 뜻이므로, Invoke(동기 호출)나 BeginInvoke(비동기 호출)를 사용하여 UI Thread로 메서드 호출을 보내야 한다. (참조: UI Thread)
아래 예제는 위의 예제중 ShowProgress부분을 고쳐쓴 것으로, InvokeRequired 속성을 체크하여 필요한 경우 (Invoke를 호출하여) UI Thread로 돌려 보내는 예이다. 여기서의 동기 호출을 위한 Invoke()에는 어뗜 함수를 호출할지를 지정하는 Delegate객체와 그 함수가 사용할 파라미터(pct)를 전달하고 있다.


예제

delegate void ShowDelegate(int percent);

private void ShowProgress(int pct)
{
   if (InvokeRequired)
   {
      ShowDelegate del = new ShowDelegate(ShowProgress);
      //또는 ShowDelegate del = p => ShowProgress(p);
      Invoke(del, pct);
   }
   else
   {
      progressBar1.Value = pct;
   }
}



C# 5.0 향상된 비동기 처리 : async / await

VS 2012 / .NET 4.5과 함꼐 등장한 C# 5.0에서는 복잡한 비동기(Asynchonous)처리를 간편하게 하기 위하여 새로운 C# 키워드인 async와 await를 도입하였고, 만약 .NET 클래스들이 이를 지원하기 위해 Async 메서드들(비동기 지원 메서드로 메서드명 끝에 대개 Async가 붙는다)을 추가하였다. 자세한 내용은 링크( C# 키워드인 async와 await )을 참조.



© csharpstudy.com