2012-03-14 2 views
3

약간의 무거운 작업을 수행하는 작은 프로젝트를 마쳤습니다. 이 짧은 계산 시간에 깨달았습니다. GUI가 멈 춥니 다. 그래서 나는 약간의 연구를했고 이것을 발견했다.>>http://www.codeproject.com/Articles/4381/Threading-out-tasks-in-a-C-NET-GUI생성자를 사용하여 새 스레드를 시작하십시오.

나는 이것이 나의 프로젝트라는 것을 구현하기 시작했는데, 나는이 특별한 구현이 내 프로젝트에서 작동하지 않는다는 것을 깨달았다.

내 프로젝트에는 많은 클래스와 다른 모든 클래스를 제어하는 ​​하나의 "관리자"가 있습니다. 이 Manager 클래스를 initilize하면 이미 생성자에서 무거운 것을 수행합니다. 내 질문에

:

은 어떻게 생성자에 새 스레드를 시작합니까?

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) 
     { 


      if (System.IO.File.Exists(e.FullPath) == true) 
      { 

       Manager mgr = new Manager(e, handreader); // here starts the heavy lifting 
       Thread mgrThread = new Thread(new ThreadStart(mgr)); // what to do ? 
       sl.Text = mgr.test(); 
       txtLog.Text = mgr.output(); 


      } 
     } 

편집 : 난 내 프로그램을 코딩하기로 결정 괜찮습니다. 이제는 무거운 짐을 싣는 것이 하나의 기능이지만 실수를 저질렀다고 생각합니다.

private void fileWatcher_Changed(object sender, System.IO.FileSystemEventArgs e) 
     { 


      if (System.IO.File.Exists(e.FullPath) == true) 
      { 
       Manager mgr = new Manager(e, handreader, txtLog, sl); 
       //sl.Invoke(new MethodInvoker(mgr.test)); 
       sl.Invoke(new MethodInvoker(mgr.test)); // first try 
       Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try 

      } 
     } 

sl.Invoke(new MethodInvoker(mgr.test)); // first try 일을하지만 여전히 내 GUI를 정지 :

전체 프로그램은 다음과 같습니다.

Thread mgrThread = new Thread(new ThreadStart(mgr.test)); // second try 

이 줄은 아무 것도 수행하지 않습니다.

내 테스트 기능 :

public void test() 
    { 
     StringBuilder builder = new StringBuilder(); 
     foreach (PlayerController pc in fm.lPc) 
     { 
      Range range = new Range(handReader.hand, handReader.handversus, pc); 
      builder.Append(pc.getHeroCardsSimple()+" vs 100% range = "+range.vsRange()+"\r\n"); 
     } 
     sl.Text = builder.ToString(); 
    } 

답변

3

이 작업에는 다른 방법을 사용해야합니다. 생성자가 여전히 GUI 스레드에서 호출됩니다.

Func<Manager> asyncConstructor; 
    private void fileSystemWatcher1_Changed(object sender, System.IO.FileSystemEventArgs e) 
    { 
     asyncConstructor = new Func<Manager>(() => new Manager()); 

     asyncConstructor.BeginInvoke(ManagerConstructed, null); 
    } 

    private void ManagerConstructed(IAsyncResult result) 
    { 
     Manager mgr = asyncConstructor.EndInvoke(result); 
     //we can only access form controls from the GUI thread, 
     //if we are not on the gui thread then 
     //do the changes on the gui thread. 
     if (this.InvokeRequired) 
     { 
      this.Invoke(new Action(() => 
      { 
       sl.Text = mgr.test(); 
       txtLog.Text = mgr.output(); 
      })); 
     } 
    } 
+1

주요 질문에 대한 답변이 있더라도 Jon과 동의합니다 : 생성자에서 과도한 작업을하지 마십시오! – ChrFin

+0

물론 네,하지만 그건 다른 질문입니다. – Bas

2
는 "노동자"어떤 종류의 생성자 밖으로 "무거운"이동 스레드에서 그 방법을 실행

.

public Manager(/*params*/) 
{ 
    //params 
    //heavy lifting 
} 

public Manager(/*params*/) 
{ 
    //params 
} 

public void DoWork() 
{ 
    //heavy lifting 
} 

Manager mgr = new Manager(e, handreader); 
Thread mgrThread = new Thread(new ThreadStart(mgr.DoWork)); 
mgrThread.Start(); 

주의에 호출 :

변경에서 관리자는 스레드에서/변경 UI 요소에 액세스하는 경우, 돈 ' 그 호출을 잊지 마라!

+0

당신의 추천을 구현하기 위해 노력했지만 성공하지 –

+0

은 그냥 편집을 확인 : 당신은 스레드를 시작하는 것을 잊었다! 내 편집을 참조하십시오 ... – ChrFin

1

글쎄, 당신은 사용 :

Thread mgrThread = new Thread(() => new Manager(e, handreader)); 

...하지만 그때 당신은 당신의 코드의 나머지 부분에 대한 관리자에 대한 참조가되지 않습니다.

사실, 생성자에서 무거운 작업을하는 것은 일반적으로 여러 가지 이유로 일반적으로 나쁜 생각입니다. 이 작업을 다른 곳으로 옮기는 것이 좋습니다.

// Constructor just sets things up 
Manager mgr = new Manager(e, handreader); 
// DoWork method does the real work 
Thread mgrThread = new Thread(mgr.DoWork); 
관련 문제