简体   繁体   English

C#Backgoundworker和跟踪栏

[英]c# backgoundworker and trackbar

I have a problem with backgroundworkers. 我的背景工作人员有问题。 I have a trackbar, and when the user changes its value, then a new backgroundworker starts. 我有一个跟踪栏,当用户更改其值时,就会启动一个新的backgroundworker。 There is a list of all backgroundworkers, and when a new one is started, all workers in the list call worker.CancelAsync() . 有一个所有后台工作人员的列表,当启动一个新的后台工作人员时,列表中的所有工作人员都调用worker.CancelAsync()

It works when a user does slow changes on the trackbar, but when you moves it very fast, there are about 20+ threads and it takes some time to kill them in WorkerCompleted . 当用户在WorkerCompleted上进行缓慢的更改时,它起作用,但是当您快速移动它时,大约有20多个线程,并且需要花费一些时间才能在WorkerCompleted杀死它们。 Also, in this function worker variables are cleaning (in this case this is a copy of bitmap), so 20+ workers needs a lot of memory and I get an OutOfMemoryException . 另外,在此函数中,工作变量正在清除(在这种情况下,这是位图的副本),因此20多名工作人员需要大量内存,而我得到了OutOfMemoryException

Is there any way to block number of threads to about 4, and when the number of backgroundworkers is equal to 4 then program will wait when they will be deleted, or is there any way to do this with only one backgroundworker, and when the trackbar value is changed it is restarted? 有什么办法可以将线程数量限制为大约4,并且当后台工作程序的数量等于4时,程序将在等待删除线程时等待,或者是否有任何办法仅使用一个后台工作程序以及在跟踪栏上执行此操作值更改是否重新启动?


Adding new 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";    
}

This is cancelling: 这是取消:

public override void CancelAllJobs()
{
    foreach (ThreadWorker worker in m_workersList)
    {
        worker.cancelled = true;
        worker.worker.CancelAsync();
    }
    debug.Text = "" + m_workersList.Count;
}

Do work: 做工作:

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 needs worker, becouse there is checking CancelationPending, setting e.Cancel=true; ProcessMainFun需要工作人员,因为正在检查CancellationPending,设置为e.Cancel = true; and return; 然后返回

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

This code-behind for a button and a label describes how you can start a single background thread and then restart it at an arbitrary position using a new starting state. 按钮和标签后面的代码描述了如何启动一个后台线程,然后使用新的启动状态在任意位置重新启动它。

In this case I choose to send an integer but you can easily send a very complex object instead. 在这种情况下,我选择发送一个整数,但是您可以轻松地发送一个非常复杂的对象。 Replace the code in CodeToRunInsideBackgroundThread(object state) with any code you need... The point is you don't need multiple threads. 用您需要的任何代码替换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();
                    })
                );
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM