• 多线程学习笔记(三) BackgroundWorker 暂停/继续


            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。

  • 相关阅读:
    pip本地源搭建
    linux 创建 bootable iso 文件
    yum 源本地化 (two)
    linux 网络配置
    linux 设置root可以远程登陆
    察看linux 发行版
    mysql bin-log 设置
    samba 奇怪问题
    delphi中的临界区
    ligerGrid 取得选中行的数据
  • 原文地址:https://www.cnblogs.com/zitjubiz/p/11533555.html
Copyright © 2020-2023  润新知