c#backgoundworker和trackbar

时间:2013-11-19 21:38:09

标签: c# backgroundworker restart trackbar

我遇到了背景工作者的问题。我有一个跟踪栏,当用户更改其值时,将启动一个新的后台工作程序。有一个所有后勤工作者的列表,当一个新工作人员启动时,列表中的所有工作人员都会调用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需要worker,因为检查CancelationPending,设置e.Cancel = true;并返回;

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

1 个答案:

答案 0 :(得分:0)

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

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