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。