I have a problem with backgroundworkers. I have a trackbar, and when the user changes its value, then a new backgroundworker starts. There is a list of all backgroundworkers, and when a new one is started, all workers in the list call worker.CancelAsync()
.
It works when a user does slow changes on the trackbar, but when you moves it very fast, there are about 20+ threads and it takes some time to kill them in WorkerCompleted
. Also, in this function worker variables are cleaning (in this case this is a copy of bitmap), so 20+ workers needs a lot of memory and I get an OutOfMemoryException
.
Is there any way to block number of threads to about 4, and when the number of backgroundworkers is equal to 4 then program will wait when they will be deleted, or is there any way to do this with only one backgroundworker, and when the trackbar value is changed it is restarted?
Adding new worker:
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";
}
This is cancelling:
public override void CancelAllJobs()
{
foreach (ThreadWorker worker in m_workersList)
{
worker.cancelled = true;
worker.worker.CancelAsync();
}
debug.Text = "" + m_workersList.Count;
}
Do work:
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 needs worker, becouse there is checking CancelationPending, setting e.Cancel=true; and return;
private void MainProcessFun(ThreadWorker worker)
{
Filters.Filters.AdvancedBlur(m_radius, m_sigma, worker);
}