难道从来没人遇到这个恶心的问题么?报错还是在主程序入口下抛出,初步调查来自MSDN解释:"DoWork  事件处理程序中的代码有可能在发出取消请求时完成其工作,轮询循环可能会错过设置为 true  的 CancellationPending。在这种情况下,即使发出了取消请求,RunWorkerCompleted  事件处理程序中 System.ComponentModel.RunWorkerCompletedEventArgs 的 Cancelled  标志也不会设置为 true。这种情况被称作争用状态,它是多线程编程中的常见问题。"我认为是这样的,我的dowork里任务十分繁重,代码巨长,涉及到文件批量拷贝,生成,图片的修改.我的取消按钮调用CancelAsync();完全按照MSDN上的写法DoWork里调用了如下方法private void Begin_Converter(BackgroundWorker worker, DoWorkEventArgs e)
        {
            if (!this.AllReady)
            {
                MessageBox.Show(this, "未准备好进行转换,请重新读取文件列表!", "信息", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return;
            }
            CreateDir();
            for (int i = 0; i < SourceFiles.Count; i++)
            {
                if (!worker.CancellationPending)
                {
                    string path = SourceFiles[i];
                    string str2 = TargetFiles[i];
                    if (!File.Exists(path))
                    {
                        switch (MessageBox.Show(this, string.Format("文件{0}不存在!", path), "文件未找到", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Hand))
                        {
                            case DialogResult.Abort:
                                //MessageBox.Show(this, "转换中止!", "信息", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                                e.Result="转换中止!";
                                bgworkerConvert.CancelAsync();
                                return;
                            case DialogResult.Ignore:
                                {
                                    continue;
                                }
                            case DialogResult.Retry:
                                {
                                    i--;
                                    continue;
                                }
                        }
                    }
                    if (File.Exists(str2) && !this.bOverlay)
                    {
                        //MessageBox.Show(this, "当前选定的目标目录已经有同名文件,请选择其它目录。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                        //showAlert("当前选定的目标目录已经有同名文件,请选择其它目录。", "提示");
                        e.Result = "当前选定的目标目录已经有同名文件,请选择其它目录。";
                        deleteCreatedDir();
                        bgworkerConvert.CancelAsync();
                        return;
                    }
                    if (this.bSinglePage && !this.bResize)
                    {
                        if (this.bDelSource && (path != str2))
                        {
                            File.Move(path, str2);
                        }
                        else
                        {
                            File.Copy(path, str2, false);
                        }
                    }
                    else
                    {
                        if (this.bSinglePage)
                        {
                            this.procSinglePage(path, str2, worker, e);
                        }
                        else if (this.bDoublePage)
                        {
                            this.procDoublePage(path, str2, worker, e);
                        }
                        else if (this.bAuto)
                        {
                            Image image = Image.FromFile(path);
                            int height = image.Height;
                            int width = image.Width;
                            image.Dispose();
                            if (height >= width)
                            {
                                if (bResize)
                                {
                                    procSinglePage(path, str2, worker, e);
                                }
                                else
                                {
                                    File.Copy(path, str2, this.bOverlay);
                                }
                            }
                            if (height < width)
                            {
                                procDoublePage(path, str2, worker, e);
                            }
                        }
                        if (this.bDelSource)
                        {
                            File.Delete(path);
                        }
                        if (progressBar1.Value < progressBar1.Maximum)
                        {
                            worker.ReportProgress(i+1);
                        }
                    }
                }
                else
                {
                     e.Cancel = true;
                     return;
                }
            }
            e.Result = "转换完成";
        }
各种取消方法都用过了,要么抛出淫荡的"调用的目标发生了异常",要么就是RunWorkerCompleted里压根无法判断BackgroundWorker到底是被取消了还是成功了!真是头疼的要死

解决方案 »

  1.   

    DoWork  事件处理程序中的代码有可能在发出取消请求时完成其工作,轮询循环可能会错过设置为 true  的 CancellationPending。在这种情况下,即使发出了取消请求,RunWorkerCompleted  事件处理程序中 System.ComponentModel.RunWorkerCompletedEventArgs 的 Cancelled  标志也不会设置为 true。这种情况被称作争用状态,它是多线程编程中的常见问题。有关多线程设计问题的更多信息,请参见 托管线程处理的最佳做法。这句话完全是废话,根本就是毫无用处,完全没说这么处理!
      

  2.   

    BackgroundWorker 提供了CancelAsync方法 ,但他仅仅是改变一个属性,并不做任何取消操作, 线程也并不会停止 ,所以需要自己在循环中去判断这个属性,适当时候退出循环如果需要即时终止线程,建议使用Thread
      

  3.   

    case DialogResult.Abort:                                e.Result="转换中止!";
                                    bgworkerConvert.CancelAsync();
                                    return;
    应该写成
          e.Cancel = true;
         return;然后在
    RunWorkerCompleted中判断e.Cancel即可
      

  4.   


    谢谢,你这个想法的缺点是:RunWorkerCompleted完全判断不出你这是取消的
      

  5.   

     bgworkerConvert.CancelAsync();
    你不能在doWork函数里面调上面那个函数.bgworkerconvert是主线程的控件,你在异步执行
    的线性程调用其函数不报异常才怪了,所有调用这个函数据的地直接return ,并且将e.cancel置为true不就得了
      

  6.   

    这么会是主线程的呢
    我的调用方法是这样:
    private void bgworkerConvert_DoWork(object sender, DoWorkEventArgs e)
            {
                BackgroundWorker worker = sender as BackgroundWorker;
                Begin_Converter(worker, e);        }
    都传递进去了的.这是按照MSDN上一个例子做的呀.使用
    e.Cancel = true;
    return;
    的结果就是,"调用的目标发生了异常"
      

  7.   

    我发应该是RunWorkerCompleted里的问题
    我把里面的东西全注释掉就不会再出这个问题,但是这么解决呢
            private void bgworkerConvert_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    MessageBox.Show(e.Error.Message);
                    return;
                }
                else if (e.Cancelled)
                {
                    // Next, handle the case where the user canceled 
                    // the operation.
                    // Note that due to a race condition in 
                    // the DoWork event handler, the Cancelled
                    // flag may not have been set, even though
                    // CancelAsync was called.
                    //showAlert("任务终止","转换任务已经被用户终止");
                    //showAlert("任务终止", e.Result.ToString());
                    MessageBox.Show(this, e.Result.ToString(), "任务取消", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }
                else
                {
                    // Finally, handle the case where the operation 
                    // succeeded.
                    if (this.progressBar1.Value > 0)
                    {
                        //showAlert("转换成功", e.Result.ToString());
                        MessageBox.Show(this, e.Result.ToString(), "完成", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                        goto lable_status;
                    }
                }
                if (e.Result.ToString().Length!=0)
                {
                    showAlert("提示", e.Result.ToString());
                }            lable_status:
                CtrlStatus(true, "convert");
            }
      

  8.   

    我在英文网站上看到有人说是读取e.Result会出现这个问题
      

  9.   

    6楼的做法测试通过。
    全部函数renturn 线程自动结束,不要终止了,加个标记判断一下终止了,前台再操作终止后的情况。