繁体   English   中英

在ProgressChanged中,backgroundworker会给出跨线程异常吗?

[英]backgroundworker gives a cross-thread exception when ProgressChanged?

我有文件传输应用程序(服务器 - 客户端)TCP [.net 4]为什么backgroundworker在(backgroundWorker1_ProgressChanged)中给我一个例外

客户端发送具有目标路径 (文件应保存到其中)的命令以及文件大小到服务器以开始接收该文件..因此,一旦服务器接受该命令,它将调用:

fileTransfer1.Receive(destPath, fileSize);

此方法在form1.cs中的自己的线程中运行:

private void Job(object o)
    {

        Socket client = (Socket)o;
        NetworkStream stream = new NetworkStream(client);
        StreamReader sr = new StreamReader(stream);

        string cmd = null;

        while ((cmd = sr.ReadLine()) != null)
        {
            string[] command = cmd.Split('<');
            switch (command[0])
            {
               case "receive":
                            fileTransfer1.Receive(command[1], Convert.ToInt64(command[2]));
                            break;
                            default:
                            break;
            }
        }

fileTransfer1(userControl)

    public void Receive(string destPath, long fileSize)
    {
            List<object> job = new List<object>();
            job.Add(destPath);
            job.Add(fileSize);
            backgroundWorker1.RunWorkerAsync(job);
    }

    long sum = 0;
    long fileSize = 0;   //this will equal the size of the file later.
    private void ReceiveFile(string destPath, long fileSize)
    {
        using (fs = new FileStream(destPath, FileMode.Create, FileAccess.Write))
        {
            try
            {
                int count = 0;
                data = new byte[packetSize];
                while (sum < fileSize)
                {
                    count = network.Read(data, 0, packetSize);
                    fs.Write(data, 0, count);
                    sum += count;
                    backgroundWorker1.ReportProgress((int)((sum * 100) / fileSize));
                }
            }
            finally
            {
                CloseTransfer();
            }
        }
    }

这是backgroundworker方法:

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
         List<object> job = (List<object>)e.Argument;
         string destPath = (string)job[1];
         long fileSize = (long)job[2];
         ReceiveFile(destPath, fileSize);
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBarFile.Position = e.ProgressPercentage;
        progressBarFile.Text = progressBarFile.Position.ToString() + "%";
  /*here*/  labelRemaining.Text = CnvrtUnit(fileSize - sum);  
    }

我遇到异常的问题(跨线程操作无效:控制'labelRemaining'从其创建的线程以外的线程访问。)引用此行:

 labelRemaining.Text = CnvrtUnit(fileSize - sum);

我知道这个异常,我知道我必须使用(委托/调用)的东西..但是..我知道背景工作者意味着这个...加上..我有相同的代码,但服务器在这里发送文件到客户..并且它没有给出异常..它工作正常,表单显示了应该的详细信息。
那么为什么我收到这个例外只是当我收到一个文件?
注意:接收方法工作正常。

您收到该错误是因为backgroundWorker1_ProgressChanged()在与创建labelRemaining控件的线程不同的线程上运行。 假设您在主UI线程上创建了labelRemaining控件,您需要:

  • 从主线程执行backgroundWorker1.RunWorkerAsync(job)

    要么

  • backgroundWorker1_ProgressChanged ,使用Dispatcher在主线程上执行对labelRemaining对象的更改,如此处所述

更新:我发现你使用的是winforms而不是WPF。 这不应该使用Dispatcher,这应该适合你: 如何从C#中的另一个线程更新GUI?

我已经想到了

因为我的命令接收器方法Void Job(对象o)在一个线程下运行..所以这个:

case "receive":
           fileTransfer1.Receive(command[1], Convert.ToInt64(command[2]));
           break;

也运行在同一个线程..这意味着其余的代码也在该线程中运行..所以我只是改变了这一行:

case "receive":
       Action a = () => fileTransfer1.Receive(command[2], Convert.ToInt64(command[3])); 
       Invoke(a);
       break;

现在UI-Thread将被通知运行其余的接收代码..这解决了我的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM