У меня проблема с фоновыми работниками. У меня есть трекбар, и когда пользователь меняет его значение, запускается новый фоновый рабочий. Есть список всех фоновых рабочих, и когда запускается новый, все рабочие в списке вызывают worker.CancelAsync()
.
Он работает, когда пользователь медленно меняет трекбар, но когда вы перемещаете его очень быстро, возникает около 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 нужен рабочий, потому что есть проверка CancelationPending, установка e.Cancel = true; и вернуться;
private void MainProcessFun(ThreadWorker worker)
{
Filters.Filters.AdvancedBlur(m_radius, m_sigma, worker);
}