멀티쓰레드 프로그램을 짜다가..

크로스 스레드 작업이 잘못되었습니다. 'txtStatus' 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다.

라는 오류가 났다.



-----------------

[C#] Form Control에는 Thread-Safe 호출을 사용


 

// This event handler creates a thread that calls a 
// Windows Forms control in an unsafe way.
private void setTextUnsafeBtn_Click(
  object sender, 
  EventArgs e)
{
  this.demoThread = 
       new Thread(new ThreadStart(this.ThreadProcUnsafe));   
  this.demoThread.Start();
}
// This method is executed on the worker thread and makes
// an unsafe call on the TextBox control.
private void ThreadProcUnsafe()
{
  this.textBox1.Text = "This text was set unsafely.";
}



위와 같이 main thread가 아닌 thread가 Windows Form의 Control을 액세스 하려고 하는 방법은 일반적으로 thread-safe 하지 않습니다.
main thread의 상태에 따라 race condition이나 deadlock이 발생할 수 있습니다.

만약에 프로그램을 디버깅 중이었다면, .NET Frame는 친절히도 아래와 같이 Exception을 발생시켜줍니다.
(이 Exception이 싫다면 CheckForIllegalCrossThreadCalls 속성을 false로 세팅하면 됩니다.)

InvalidOperationException was unhandled
크로스 스레드 작업이 잘못되었습니다. 'txtStatus' 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다.




그렇다면 Thread-Safe한 방법은 무엇일까요?


delegate void SetTextCallback(string text);

// This event handler creates a thread that calls a 
// Windows Forms control in a thread-safe way. 
private void setTextSafeBtn_Click( 
            object sender, 
            EventArgs e)
{
    this.demoThread = 
    new Thread(new ThreadStart(this.ThreadProcSafe));

    this.demoThread.Start();
}
// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
private void ThreadProcSafe()
{
    this.SetText("This text was set safely.");
}

// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control. 
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.

private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (this.textBox1.InvokeRequired)
    { 
         SetTextCallback d = new SetTextCallback(SetText);
         this.Invoke(d, new object[] { text });
    }
    else
    {
         this.textBox1.Text = text;
    }
}



위와 같이 delegate를 하나 만든 다음 
Form의 Control에 InvokeRequired 속성이 true일때
Form에서 Invoke 함수로 해당 함수를 다시 호출하게 하면 됩니다.


MFC를 사용할 때는 참 난감했었는데, C#은 참 쉽지요?


http://msdn2.microsoft.com/en-us/library/ms171728.aspx


-------------------



나의 경우는 디버거만 붙이면 저런 현상이 나타났는데... (디버거 안붙이면 정상실행됨)

간단하게 그냥

Control.CheckForIllegalCrossThreadCalls = false;

로 해결하였다.

'C#, .NET' 카테고리의 다른 글

가변인자 사용하기 - params 키워드  (0) 2011.06.17
textbox 에서 엔터쳤을때의 처리  (0) 2011.06.17
분수(Fraction) 클래스 (자체제작)  (0) 2011.06.17
Invader  (0) 2011.06.17
Entity Framework  (0) 2011.06.17
Posted by 휘사마
,