随笔 - 312  文章 - 10  评论 - 89  2
        BackgroundWorker bw;
        private ManualResetEvent manualReset = new ManualResetEvent(true);

        private void button3_Click(object sender, EventArgs e)
        {
            using ( bw = new BackgroundWorker())
            {
                bw.WorkerReportsProgress = true;
                bw.WorkerSupportsCancellation = true;
                bw.ProgressChanged += bw_ProgressChanged;
                bw.RunWorkerCompleted += bw_RunWorkerCompleted;
                bw.DoWork += bw_DoWork;

                //允许用户指定显示数据的范围呢!所以需要把100作为参数传递给计算过程
                bw.RunWorkerAsync(100); 
            }

        }
        //这时返回了主线程,所以可以直接使用UI控件了
        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //修改进度条的显示。
            //this.progressBarSum.Value = e.ProgressPercentage;

            //如果有更多的信息需要传递,可以使用 e.UserState 传递一个自定义的类型。
            //这是一个 object 类型的对象,您可以通过它传递任何类型。
            //我们仅把当前 sum 的值通过 e.UserState 传回,并通过显示在窗口上。
            string message = e.UserState.ToString();
            label1.Text = message;
        }
        //e.Argument=bw.RunWorkerAsync("Hello World")的参数
        void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("bw_DoWork");

            BackgroundWorker bgWorker = sender as BackgroundWorker;


            //这里的操作是在另一个线程上完成的,不应该操作UI
            //在这里执行耗时的运算。

            int endNumber = 0;
            if (e.Argument != null)
            {
                endNumber = (int)e.Argument;
            }

            for (int i = 0; i <= endNumber; i++)
            {
                manualReset.WaitOne();
                //如果ManualResetEvent的初始化为终止状态(true),那么该方法将一直工作,
                //直到收到Reset信号。然后,直到收到Set信号,就继续工作。

                bgWorker.ReportProgress(i, "current num:" + i.ToString());
                Thread.Sleep(500); //为了方便演示
                if (bgWorker.CancellationPending)
                {
                    e.Cancel = true;
                    System.Diagnostics.Debug.WriteLine("CancellationPending");
                    break;
                }

            }

        }
        //停止
        private void button4_Click(object sender, EventArgs e)
        {
            bw.CancelAsync();
        }
        //暂停/继续
        private void button5_Click(object sender, EventArgs e)
        {
            if (btnPause.Text == "暂停")
            {
                manualReset.Reset();//暂停当前线程的工作,发信号给waitOne方法,阻塞
                btnPause.Text = "继续";
            }
            else
            {
                manualReset.Set();//继续某个线程的工作
                btnPause.Text = "暂停";
            }
        } 

请注意红色字体, 采用信号量 ManualResetEvent来控制暂停/继续

 

    ManualResetEvent 允许线程通过发信号互相通信。通常,此通信涉及一个线程在其他线程进行之前必须完成的任务。当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时,它调用 Reset 以将 ManualResetEvent 置于非终止状态,此线程可被视为控制 ManualResetEvent。调用 ManualResetEvent 上的 WaitOne 的线程将阻止,并等待信号。当控制线程完成活动时,它调用 Set 以发出等待线程可以继续进行的信号。并释放所有等待线程。一旦它被终止,ManualResetEvent 将保持终止状态(即对 WaitOne 的调用的线程将立即返回,并不阻塞),直到它被手动重置。可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。

posted on 2019-09-17 14:30  Gu  阅读(...)  评论(...编辑  收藏