我的背景工作人员有问题。我有一个跟踪栏,当用户更改其值时,就会启动一个新的backgroundworker。这里有所有后台工作人员的列表,并且当一个新的后台工作人员启动时,列表中的所有工作人员都会调用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);
}


工人完成:

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需要工作人员,因为正在检查CancellationPending,设置为e.Cancel = true;然后返回

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

最佳答案

按钮和标签后面的代码描述了如何启动一个后台线程,然后使用新的启动状态在任意位置重新启动它。

在这种情况下,我选择发送一个整数,但是您可以轻松地发送一个非常复杂的对象。用您需要的任何代码替换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();
                    })
                );
            }
        }
    }
}

关于c# - C#Backgoundworker和跟踪栏,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20082616/

10-11 02:13