У меня проблема с фоном. У меня есть трек-бэк, и когда пользователь меняет свое значение, начинается новый фоном. Список всех фоновых работников, и когда начинается новый, все рабочие в списке звонят 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);
}
Вы должны показать, что вы в настоящее время пытаетесь ввести код, или вы рискуете, что ваш вопрос будет закрыт. –
Если фонового работника недостаточно, вам может понадобиться использовать threadpool. Возможно, у вас есть собственные коллекции потоков, которыми вы управляете самостоятельно ... – Noctis
Нет сценария, когда ваш тест на CancellationPending внутри метода DoWork когда-либо будет правдой, вы тестируете его через микросекунду после того, как вы вызвали DoWork. Нет никакого сценария, когда «ThreadWorker» мог когда-либо знать, что BackgroundWorker.CancellationPending всегда прав. Так что это не сработает, кабум. Продвигайтесь вперед, не запуская BGW, пока не истечет какое-то время или не добавит кнопку DoIt. –