为什么当我点击取消操作时,它不会马上停止背景工作者?

时间:2013-10-15 17:12:28

标签: c# winforms backgroundworker

这是我有两名背景工作者的背景工作者。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HtmlAgilityPack;
using System.Net;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;

namespace GatherLinks
{
    class BackgroundWebCrawling
    {
        public string f;
        int counter = 0;
        List<string> WebSitesToCrawl;
        int MaxSimultaneousThreads;
        public BackgroundWorker mainBackGroundWorker;
        BackgroundWorker secondryBackGroundWorker;
        WebcrawlerConfiguration webcrawlerCFG;
        List<WebCrawler> webcrawlers;
        int maxlevels;
        public event EventHandler<BackgroundWebCrawlingProgressEventHandler> ProgressEvent;
        ManualResetEvent _busy = new ManualResetEvent(true);


        public BackgroundWebCrawling()
        {
            webcrawlers = new List<WebCrawler>();
            mainBackGroundWorker = new BackgroundWorker();
            mainBackGroundWorker.WorkerSupportsCancellation = true;
            mainBackGroundWorker.DoWork += mainBackGroundWorker_DoWork;
        }

        private void mainBackGroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                for (int i = 0; i < WebSitesToCrawl.Count; i++)
                {
                    _busy.WaitOne();
                    if ((worker.CancellationPending == true))
                    {
                        e.Cancel = true;
                        break;
                    }
                    while (counter >= MaxSimultaneousThreads)
                    {
                        Thread.Sleep(10);
                    }


                    WebCrawler wc = new WebCrawler(webcrawlerCFG);
                    webcrawlers.Add(wc);
                    counter++;
                    secondryBackGroundWorker = new BackgroundWorker();
                    secondryBackGroundWorker.DoWork += secondryBackGroundWorker_DoWork;
                    object[] args = new object[] { wc, WebSitesToCrawl[i] };
                    secondryBackGroundWorker.RunWorkerAsync(args);



                }
                while (counter > 0)
                {
                    Thread.Sleep(10);
                }
            }
            catch
            {
                MessageBox.Show("err");
            }
        }

        private void secondryBackGroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {


            try
            {
                object[] args = (object[])e.Argument;
                WebCrawler wc = (WebCrawler)args[0];
                string mainUrl = (string)args[1];
                wc.ProgressEvent += new EventHandler<WebCrawler.WebCrawlerProgressEventHandler>(x_ProgressEvent);
                wc.webCrawler(mainUrl, maxlevels);


                counter--;
            }
            catch
            {
                MessageBox.Show("err");
            }
        }

        public void Start(List<string> sitestocrawl, int threadsNumber, int maxlevels, WebcrawlerConfiguration wccfg)
        {
            this.maxlevels = maxlevels;
            webcrawlerCFG = wccfg;
            WebSitesToCrawl = sitestocrawl;
            MaxSimultaneousThreads = threadsNumber;
            mainBackGroundWorker.RunWorkerAsync();
        }

        private void x_ProgressEvent(object sender, WebCrawler.WebCrawlerProgressEventHandler e)
        {

            Object[] temp_arr = new Object[8];
            temp_arr[0] = e.csFiles;
            temp_arr[1] = e.mainUrl;
            temp_arr[2] = e.levels;
            temp_arr[3] = e.currentCrawlingSite;
            temp_arr[4] = e.sitesToCrawl;
            temp_arr[5] = e.done;
            temp_arr[6] = e.failedUrls;
            temp_arr[7] = e.failed;
            OnProgressEvent(temp_arr); 
        }

        private void GetLists(List<string> allWebSites)
        {

        }

        public class BackgroundWebCrawlingProgressEventHandler : EventArgs
        {
            public List<string> csFiles { get; set; }
            public string mainUrl { get; set; }
            public int levels { get; set; }
            public List<string> currentCrawlingSite { get; set; }
            public List<string> sitesToCrawl { get; set; }
            public bool done { get; set; }
            public int failedUrls { get; set; }
            public bool failed { get; set; }
        }

        protected void OnProgressEvent(Object[] some_params) 
        {


            if (ProgressEvent != null)
                ProgressEvent(this,
                    new BackgroundWebCrawlingProgressEventHandler()
                    {
                        csFiles = (List<string>)some_params[0],
                        mainUrl = (string)some_params[1],
                        levels = (int)some_params[2],
                        currentCrawlingSite = (List<string>)some_params[3],
                        sitesToCrawl = (List<string>)some_params[4],
                        done = (bool)some_params[5],
                        failedUrls = (int)some_params[6],
                        failed = (bool)some_params[7]
                    });
        }

        private void PauseWorker()
        {
            if (mainBackGroundWorker.IsBusy)
            {
                _busy.Reset();
            }
        }

        private void ContinueWorker()
        {
            _busy.Set();
        }

        public void CancelWorker()
        {
            ContinueWorker();
            mainBackGroundWorker.CancelAsync();
        }

    }
}

这是单击以中止操作的按钮单击事件:

private void button3_Click(object sender, EventArgs e)
        {
            bgwc.CancelWorker();
            cancel = true;
            wcfg.toCancel = cancel;
        }

当我点击按钮时,它会转到BackgroundWebCrawling类并执行:

public void CancelWorker()
        {
            ContinueWorker();
            mainBackGroundWorker.CancelAsync();
        }

但是由于某种原因而不是立即停止背景工作者等待/挂起它直到它将完成当前进程大约2-3-5秒然后停止。 而是立即停止进入Form1并执行此部分:

private void bgwc_ProgressEvent(object sender, BackgroundWebCrawling.BackgroundWebCrawlingProgressEventHandler e)
        {
            this.Invoke(new MethodInvoker(delegate { label7.Text = e.sitesToCrawl.Count.ToString(); }));
            this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, "Level: " + e.levels.ToString(), Color.Green); }));
            this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, "   Loading The Url:   ", Color.Red); }));
            this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, e.mainUrl + "...", Color.Blue); }));
            if (e.done == true)
            {


                    this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Done " + Environment.NewLine, Color.Red); }));
                    doneWebPages++;
                    this.Invoke(new MethodInvoker(delegate { label12.Text = doneWebPages.ToString(); }));

            }
            if (e.failed == true)
            {
                this.Invoke(new MethodInvoker(delegate { label10.Text = e.failedUrls.ToString(); }));
                this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Failed " + Environment.NewLine, Color.Green); }));
            }
            if (e.failedUrls > 0)
            {
                this.Invoke(new MethodInvoker(delegate { label10.Text = e.failedUrls.ToString(); }));
                e.failed = true;
                if (e.failed == true)
                {
                    this.Invoke(new MethodInvoker(delegate { ColorText.Texts(richTextBox1, " Failed " + Environment.NewLine, Color.Green); }));
                    e.failed = false;
                }
            }
            this.Invoke(new MethodInvoker(delegate { label13.Text = (e.failedUrls + doneWebPages).ToString(); }));
        }

之后它回到BackgroundWebCrawling类并执行此操作:

if (ProgressEvent != null)
                ProgressEvent(this,
                    new BackgroundWebCrawlingProgressEventHandler()
                    {
                        csFiles = (List<string>)some_params[0],
                        mainUrl = (string)some_params[1],
                        levels = (int)some_params[2],
                        currentCrawlingSite = (List<string>)some_params[3],
                        sitesToCrawl = (List<string>)some_params[4],
                        done = (bool)some_params[5],
                        failedUrls = (int)some_params[6],
                        failed = (bool)some_params[7]
                    });

然后在同一个班级做这一行:

OnProgressEvent(temp_arr); ///将此类的数据+附加数据发送到Form1 ..

毕竟这是在Form1中完成的事件:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            button3.Enabled = false;
            checkBox1.Enabled = true;
            checkBox2.Enabled = true;
            numericUpDown1.Enabled = true;
            button1.Enabled = true;
            button2.Enabled = true;
            this.Text = "Web Crawling";
            if (cancel == true)
            {
                label6.Text = "Process Cancelled";
            }

问题是当我点击按钮并等待首先完成该过程时,为什么它不会中止操作? 也许我需要以某种方式停止/中止第二个背景?

1 个答案:

答案 0 :(得分:0)

首先,这看起来像是矫枉过正的代码,但也许有必要......

其次,你的取消实际上并没有取消任何东西,它只是设置了你必须采取行动的标志,当你回复那个标志时,你只是break,那么你等待计数到返回0.如果您想立即停止,请不要breakreturn

休息之后,你仍然在你的工作人员中做以下事情。您也可以在取消时将counter设置为0。但是,回报更具有前瞻性。

while (counter > 0)
{
    Thread.Sleep(10);
}