c# backgoundworker 和 trackbar

标签 c# backgroundworker restart trackbar

我对后台工作人员有疑问。我有一个 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/

相关文章:

c# - ASP.NET MVC 中的面向方面编程

C# JsonConverter 无法从 JsonResult 反序列化对象

c# - 从 BackgroundWorker C# 调用的 CoInitialize

c# - UI 仍然卡住使用 backgroundWorker

c# - 如何记录 BackgroundWorker.RunWorkerAsync(Object) 的参数?

android - 被 "Advanced Task Killer"之类的应用程序杀死后如何重新启动服务?

windows - 独立的 ruby​​ 脚本(windows 和 mac)可以重新加载并重新启动吗?

java - 如果鼠标正在移动,则重新启动计时器

c# - DbContext Unity 不调用 HttpContextLifetimeManager.RemoveValue() 坏事?

c# - 在 WinRT 中从 C# 解析 JSON