2013-11-19 2 views
2

У меня проблема с фоном. У меня есть трек-бэк, и когда пользователь меняет свое значение, начинается новый фоном. Список всех фоновых работников, и когда начинается новый, все рабочие в списке звонят worker.CancelAsync().C# backgoundworker и trackbar

Это работает, когда пользователь делает медленные изменения на трекбаре, но когда вы двигаете его очень быстро, существует около 20 + потоков, и требуется некоторое время, чтобы убить их в WorkerCompleted. Кроме того, в этой функции рабочие переменные очищаются (в этом случае это копия растрового изображения), поэтому 20+ работникам требуется большая память, и я получаю OutOfMemoryException.

Есть ли способ блокировать количество потоков примерно до 4, а когда количество фоновых работников равно 4, тогда программа будет ждать, когда они будут удалены, или есть ли способ сделать это только с одним фоном, и когда значение трекбара изменяется, оно перезапускается?


Добавление нового работника:

public override void StartWorker(Bitmap bmp, bool needTempImage) 
{ 
    if(m_workersList.Count<maxThread) 
    { 
     CancelAllJobs(); 

     // debug.Text = "locked"; 
     BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); 

     imageDataAttributes imgAttr = new imageDataAttributes(bd.Width, bd.Height, bd.Stride, 4); 

     ThreadWorker worker = new ThreadWorker(needTempImage, bd.Scan0, imgAttr); 
     bmp.UnlockBits(bd); 

     m_workersList.Add(worker); 
     m_currentWorker = worker; 
     worker.worker.WorkerSupportsCancellation = true; 
     worker.worker.DoWork += WorkerDoWork; 
     worker.worker.WorkerReportsProgress = report; 

     if (report == true) 
     { 
      worker.worker.ProgressChanged += WorkerProgress; 
      m_progressBar.Visible = true; 
     } 

     worker.worker.RunWorkerCompleted += WorkerCompleted; 
     worker.worker.RunWorkerAsync(worker); 

     debug.Text = "" + m_workersList.Count; 
    } 
    //debug.Text = "unlocked";  
} 

Это отменяя:

public override void CancelAllJobs() 
{ 
    foreach (ThreadWorker worker in m_workersList) 
    { 
     worker.cancelled = true; 
     worker.worker.CancelAsync(); 
    } 
    debug.Text = "" + m_workersList.Count; 
} 

ли работа:

protected override void WorkerDoWork(object sender, DoWorkEventArgs e) 
{ 
    ThreadWorker worker = (ThreadWorker)e.Argument; 
    if (worker.worker.CancellationPending == true) 
    { 
     e.Cancel = true; 
     worker.cancelled = true; 
     return; 
    } 

    WorkerProcessFun(worker); 
} 

WorkerCompleted:

protected override void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    ThreadWorker worker = m_workersList.Find(w => w.worker == sender); 

    if (!worker.cancelled && worker == m_currentWorker) 
    { 
     if (e.Error != null) 
     { 
      MessageBox.Show("Worker Thread Error " + e.Error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 
     } 
     else 
     { 
      WorkerOnCompleteFun(worker.imgDataArray); 
     } 
    } 

    m_workersList.Remove(worker); 
    worker.Clean(); 
    if (worker == m_currentWorker) m_currentWorker = null; 
    debug.Text = "" + m_workersList.Count; 
} 

ProcessMainFun нуждается в работнике, потому что есть проверка ОтменаPending, установка e.Cancel = true; и вернуться;

private void MainProcessFun(ThreadWorker worker) 
{ 
    Filters.Filters.AdvancedBlur(m_radius, m_sigma, worker); 
} 
+0

Вы должны показать, что вы в настоящее время пытаетесь ввести код, или вы рискуете, что ваш вопрос будет закрыт. –

+0

Если фонового работника недостаточно, вам может понадобиться использовать threadpool. Возможно, у вас есть собственные коллекции потоков, которыми вы управляете самостоятельно ... – Noctis

+0

Нет сценария, когда ваш тест на CancellationPending внутри метода DoWork когда-либо будет правдой, вы тестируете его через микросекунду после того, как вы вызвали DoWork. Нет никакого сценария, когда «ThreadWorker» мог когда-либо знать, что BackgroundWorker.CancellationPending всегда прав. Так что это не сработает, кабум. Продвигайтесь вперед, не запуская BGW, пока не истечет какое-то время или не добавит кнопку DoIt. –

ответ

0

Этот код фоновый для кнопки и этикетки описывает, как вы можете создать единый фоновый поток, а затем перезапустить его в произвольном положении с помощью нового стартового состояния.

В этом случае я хочу отправить целое число, но вы можете просто отправить очень сложный объект. Замените код в CodeToRunInsideBackgroundThread (состояние объекта) с любым кодом, который вам нужен ... Дело в том, что вам не нужно несколько потоков.

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     Thread backgroundWorker = null; 
     int startingThreadState = 0; 

     private void button1_Click(object sender, EventArgs e) 
     { 
      startingThreadState += 100; 
      if (backgroundWorker == null || !backgroundWorker.IsAlive) 
      { 
       InitThread(); 
       backgroundWorker.Start(startingThreadState); 
      } 
      else 
      { 
       backgroundWorker.Abort(startingThreadState); 
      } 
     } 

     private void InitThread() 
     { 
      backgroundWorker = new Thread(new ParameterizedThreadStart((state)=> 
       { 
        while (true) 
        { 
         try 
         { 
          CodeToRunInsideBackgroundThread(state); 
          break;//while(true) 
         } 
         catch (ThreadAbortException ex) 
         { 
          System.Threading.Thread.ResetAbort(); 
          state = startingThreadState;// state available in ex.Data here? 
         } 
        } 
       })); 
      backgroundWorker.IsBackground = true; 
     } 

     private void CodeToRunInsideBackgroundThread(object state) 
     { 
      for (int i = (int)state; i < (int)state + 3; i++) 
      { 
       System.Threading.Thread.Sleep(1000); 
       this.Invoke(
        new Action(() => 
        { 
         label1.Text = i.ToString(); 
        }) 
       ); 
      } 
     } 
    } 
} 
+0

Я попробую написать свой код, используя Thread вместо BackgroundWorker, becouse Thread можно убить с помощью Abort, и я думаю, что это мне поможет. У Bgworker есть только CancelAsync, который не убивает поток сразу, я думаю. –

Смежные вопросы