我对后台工作人员有疑问。我有一个 trackbar,当用户改变它的值时,一个新的 backgroundworker 就会启动。有一个包含所有后台 worker 的列表,当启动一个新的后台 worker 时,列表中的所有 worker 都会调用 worker.CancelAsync()
。
当用户在轨迹栏上进行缓慢的更改时,它会起作用,但是当您快速移动它时,大约有 20 多个线程,并且需要一些时间才能在 WorkerCompleted
中杀死它们。此外,在此函数中,worker 变量正在清理(在本例中,这是位图的副本),因此 20 多个 worker 需要大量内存,我得到了 OutOfMemoryException
。
有没有什么方法可以将线程数限制在 4 个左右,当后台工作人员的数量等于 4 时,程序将等待它们被删除,或者有什么办法只用一个后台工作人员来做到这一点,以及当 trackbar 值改变时它会重新启动吗?
添加新 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";
}
这是取消:
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);
}
worker 完成:
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 需要 worker,因为有检查 CancelationPending,设置 e.Cancel=true;并返回;
private void MainProcessFun(ThreadWorker worker)
{
Filters.Filters.AdvancedBlur(m_radius, m_sigma, worker);
}
最佳答案
此按钮和标签的代码隐藏描述了如何启动单个后台线程,然后使用新的起始状态在任意位置重新启动它。
在这种情况下,我选择发送一个整数,但您可以轻松地发送一个非常复杂的对象。将 CodeToRunInsideBackgroundThread(object state) 中的代码替换为您需要的任何代码...重点是您不需要多线程。
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();
})
);
}
}
}
}
关于c# backgoundworker 和 trackbar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20082616/