2010-12-17 5 views
3

내 작업은 하나의 문제를 제외하고는 모두 완료되었습니다. beginboxdate() 및 endupdate()를 통해 목록 상자 UI의 업데이트를 제어하고 있는데, 이는 진행률 막대를 업데이트하는 데 사용되는 backgroundWorker 스레드를 통해 이루어집니다. 나는 항목 목록에 대한 자물쇠 나 모니터로 충분하다고 생각했지만 (그림을 그릴 때 목록을 분석해야하는 경우) 아무 소용이 없다. 아무도 아이디어가 없나요?멀티 스레드 환경에서 listbox.BeginUpdate/listbox.EndUpdate를 사용하면 작동하지 않습니다.

여기에 편집

... 관련 코드입니다 : 다른 스레드를 통해 목록에 항목의 추가 표시합니다.

private void backgroundWorker4_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // Get the BackgroundWorker that raised this event. 
     BackgroundWorker worker = sender as BackgroundWorker; 

     // Number of intervals 
     int stop = 60; 

     for (int i = 1; i <= stop; i++) 
     { 
      if (worker.CancellationPending) 
      { 
       e.Cancel = true; 
       backgroundWorker4.ReportProgress(0); 
       return; 
      } 

      //listBoxBeginUpdate(listBox1); 

      // Half second intervals 
      //listBox1.BeginUpdate(); 
      //listBox1.EndUpdate(); 
      //ListBox.listBoxBeginUpdate(listBox1); 
      listBoxBeginUpdate(listBox1); 
      Thread.Sleep(500); 
      listBoxEndUpdate(listBox1); 

      listBoxBeginUpdate(listBox1); 
      Thread.Sleep(500); 
      listBoxEndUpdate(listBox1); 

      // Update every second 
      //listBoxEndUpdate(listBox1); 

      int progress = i * 100/stop; 
      backgroundWorker4.ReportProgress(progress); 

      //updateProgressBar = !updateProgressBar; 
     } 
    } 
public static void listBoxBeginUpdate(System.Windows.Forms.ListBox varListBox) 
    { 
     if (varListBox.InvokeRequired) 
     { 
      varListBox.BeginInvoke(new MethodInvoker(() => listBoxBeginUpdate(varListBox))); 
     } 
     else 
     { 
      // Request the lock, and block until it is obtained. 
      Monitor.Enter(varListBox); 
      try 
      { 
       // When the lock is obtained, add an element. 
       varListBox.BeginUpdate(); 
      } 
      finally 
      { 
       // Ensure that the lock is released. 
       Monitor.Exit(varListBox); 
      } 
     } 
    } 

    public static void listBoxEndUpdate(System.Windows.Forms.ListBox varListBox) 
    { 
     if (varListBox.InvokeRequired) 
     { 
      varListBox.BeginInvoke(new MethodInvoker(() => listBoxEndUpdate(varListBox))); 
     } 
     else 
     { 
       // Request the lock, and block until it is obtained. 
       Monitor.Enter(varListBox); 
       try 
       { 
       // When the lock is obtained, add an element. 
        varListBox.EndUpdate(); 
       } 
       finally 
       { 
       // Ensure that the lock is released. 
        Monitor.Exit(varListBox); 
       } 

      //lock (varListBox.Items) 
      //{ 
      // Monitor.Enter(varList 
      // varListBox.EndUpdate(); 
      //} 
     } 
    } 

// Added to show the thread adding items into the list 
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     // Get the BackgroundWorker that raised this event. 
     BackgroundWorker worker = sender as BackgroundWorker; 
     Random random = new Random(); 

     //Stopwatch stopwatch = new Stopwatch(); 
     //stopwatch.Start(); 

     while(_threadsRunning) 
     { 
      if (worker.CancellationPending) 
      { 
       e.Cancel = true; 
       return; 
      } 

      System.Threading.Thread.Sleep(1000); 

      int numberOfItems = random.Next(5, 10); 
      for (int i = 5; i < numberOfItems; i++) 
      { 
       int number = random.Next(1, 10000); 
       listBoxAddItem(listBox1, number); 
      } 

      backgroundWorker1.ReportProgress(numberOfItems); 
     } 
    } 

public static void listBoxAddItem(System.Windows.Forms.ListBox varListBox, int item) 
    { 
     if (varListBox.InvokeRequired) 
     { 
      varListBox.BeginInvoke(new MethodInvoker(() => listBoxAddItem(varListBox, item))); 
     } 
     else 
     { 
      varListBox.Items.Add(item); 
     } 
    } 
+0

오류가 발생합니까? –

+0

목록 자체가 비어 있지만 스크롤 막대 증가로 항목이 계속 추가되고 있음을 알 수 있습니다 (예상). 루프가 완료 될 때까지 목록에 다시 채워지지 않습니다. 방금 루프를 5 초 타이머로 테스트했지만 약 4 초 후에 다시 채워졌습니다. – steveng39

+0

누락 되었습니까? 항목이 목록 상자에 추가되는 위치는 어디입니까? –

답변

2

이것은 다소 복잡합니다. 당신은 backgroundWorker1을 가지고 있습니다. 메시지를 Control.BeginInvoke을 통해 UI 스레드에 보내어 ListBox에 항목을 추가하는 것보다 조금 더 많은 작업을 수행하는 것처럼 보입니다. 동시에 backgroundWorker4BeginUpdateEndUpdate을 호출하도록 UI 스레드에 메시지를 보내는 것 이상을 수행하지 않습니다.

  • UI 업데이트가 UI 스레드에서 계속 발생합니다. UI 요소를 만든 스레드가 아닌 다른 스레드에서 UI 요소에 절대 액세스 할 수 없기 때문에 좋은 점이 하나 있습니다. 그러나 작업자 스레드는 UI 스레드에 메시지를 보내는 것 이상을 수행하지 않으므로 거의 무의미합니다. 사실, 실제로는 상황이 느려집니다.

  • BeginUpdate, EndUpdateAdd 방법의 시퀀싱은 완전히 무작위로 진행됩니다. 나는 당신이 이후의 행동을하지 않을 것이라고 내기하고 있습니다.

  • 잠금 장치 (Monitor.EnterMonitor.Exit 통해)는 무의미합니다. 잠금은 UI 스레드에서만 획득되므로 절대 절대로 경합이 발생하지 않습니다.

  • UI와 작업자 스레드 간의 갭을 메우기 위해 Control.BeginInvoke 또는 Control.Invoke을 사용하면 남용됩니다. 개인적으로이 주제가 argumentum ad populum의 희생양이라고 생각합니다. 많은 경우 UI 스레드가 주기적으로 (System.Windows.Forms.Timer을 통해) 작업자 스레드가 업데이트하는 공유 데이터 구조를 폴링하도록하는 것이 좋습니다.

+0

그래서 공유 데이터 구조를 폴링하는 것이 더 나을 것이라고 생각합니다. 덜 복잡하고 정보 소스를 쉽게 제어 할 수 있습니다. 다시 말하지만, 원래 질문에 대한 나의 마지막 코멘트를 읽는다면, 문제 자체가 그것을 요구했기 때문에이 코드가 작성된 것을 볼 수있을 것입니다. 이 문제는 스레드가 UI 스레드에 메시지를 보내도록 요청하고 진행률 표시 줄을 업데이트하고 목록 내용을 0.5 초마다 업데이트하는 또 다른 스레드를 요청했습니다. – steveng39

관련 문제