c# 意外的 backgroundWorker 行为

c# unexpected backgroundWorker behaviour

我已将 backgroundWorker 组件附加到我的主窗体,该组件 运行 是为动画 gif 捕获屏幕的并行任务。工作人员的函数有一个 运行s 的 while 循环,直到我在工作人员上使用 CancelAsync(),此时它退出循环,做一些其他事情,比如保存 gif 文件等等 returns UI 线程的一些结果。

private bool capturing = false;

public MainForm()
{
    InitializeComponent();
    backgroundWorker.DoWork += backgroundWorker_DoWork;
    backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
    backgroundWorker.WorkerSupportsCancellation = true;
}

private void captureBtn_Click(object sender, EventArgs e)
{
    Debug.WriteLine("Button clicked");
    if (capturing) { return; }
    if (!backgroundWorker.IsBusy)
    {
        backgroundWorker.RunWorkerAsync();
    }
}

private void stopCaptureBtn_Click(object sender, EventArgs e)
{
    if (backgroundWorker.IsBusy)
    {
        backgroundWorker.CancelAsync();
    }
}

private void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
    capturing = true;
    Debug.WriteLine("DoWork running");

    while (!backgroundWorker.CancellationPending)
    {
        Debug.WriteLine("Capturing frame {0}", frames);
        //do the capturing to memory stream
    }

    Debug.WriteLine("DoWork cancelled");

    //do some other things like saving the gif etc
    e.Result = someResult;
}

private void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
    Debug.WriteLine("RunWorkerCompleted running");
    capturing = false;
    //does something with the e.Result
}

正常测试期间我的控制台输出是这样的:

Button clicked
DoWork running
Capturing frame 0
Capturing frame 1
Capturing frame 2
Capturing frame 3
Capturing frame 4
Capturing frame 5
Cancel button clicked
DoWork cancelled
The thread 0x2e4c has exited with code 0 (0x0).
DoWork running
DoWork cancelled
The thread 0x1010 has exited with code 0 (0x0).
RunWorkerCompleted running

函数似乎 运行ning 两次,我可以看到 2 个单独的线程退出,而且我似乎没有从捕获中获得任何结果。如果我在 backgroundWorker_DoWork 函数内设置断点并稍后继续,第一个 运行 会正常进行捕获。可能发生了什么?

线程 0x3108 已退出,代码 0 (0x0) 表示没有错误。 在读取或写入大数据时,您应该将其分成几部分。否则,你无法进步。写入内存流时,您当前的 while 循环被禁用。 所以你的 backgroundWorker_DoWork 方法应该是这样的:

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        var worker = (BackgroundWorker)sender;

        // this is an example file
        string filePath = @"C:\file.gif";

        // it determines how many bytes of data will be received from the stream each time.
        byte[] buffer = new byte[4096];
        int byteCount = 0;

        // we are preparing to read stream.
        using (FileStream fs = new FileStream(filePath, FileMode.Open, System.IO.FileAccess.Read))
        using (MemoryStream ms = new MemoryStream())
        {
            // read the stream bytes and fill buffer
            while ((byteCount = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                // if the task was canceled
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }

                // write buffer to memory stream
                ms.Write(buffer, 0, byteCount);
            }
        }
    }

它被调用两次,因为在 InitializeComponent() 之后第二次绑定事件。 只需评论这些行,它应该可以正常工作。 这是没有 运行 两次问题的相同示例。

示例输出 ... ... ... 捕获帧 2632 捕获帧 2633 捕获帧 2634 取消工作 RunWorkerCompleted 运行

public partial class Form1 : Form
    {
        private bool capturing = false;
        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.WorkerSupportsCancellation = true;

  // Don't need to re-bind
            //backgroundWorker1.DoWork += backgroundWorker1_DoWork;
            //backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
            //backgroundWorker1.WorkerSupportsCancellation = true;
        }



private void captureBtn_Click(object sender, EventArgs e)
        {
            Debug.WriteLine("Button clicked");
            if (capturing) { return; }
            if (!backgroundWorker1.IsBusy)
            {
                backgroundWorker1.RunWorkerAsync();
            }
        }

        private void stopCaptureBtn_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.IsBusy)
            {
                backgroundWorker1.CancelAsync();
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            capturing = true;
            Debug.WriteLine("DoWork running");
            int frames = 1;

            while (!backgroundWorker1.CancellationPending)
            {
                Debug.WriteLine("Capturing frame {0}", frames);
                //do the capturing to memory stream
                frames++;
            }

            Debug.WriteLine("DoWork cancelled");

            //do some other things like saving the gif etc
            //e.Result = someResult;
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Debug.WriteLine("RunWorkerCompleted running");
            capturing = false;
            //does something with the e.Result
        }