2012-03-05 46 views
0

我有文件传输应用程序(服务器端)TCP [.NET 4] 为什么BackgroundWorker的给我(backgroundWorker1_ProgressChanged)异常backgroundworker在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(用户控件)

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); 

我知道这个异常,我知道我必须使用(委托/调用)的事情..但..我知道backgroundworker意味着这.. ..加..我有相同的代码,但服务器这里发送一个文件给客户端..它并没有给出这个例外..它工作正常,表格显示我的细节,因为它应该是。
那么,为什么我只是当我收到一个文件时得到这个异常?
注意:接收方法工作正常。

+0

哪个表单托管BackgroundWorker?是否有Chrome浏览器或IE显示的“下载进度”弹出窗口? – 2012-03-05 18:56:46

+0

@ChrisShain不接受它在该主表单中的userControl ..它接收文件并显示接收进度。 – 2012-03-05 18:58:05

+0

n/m在这个例外中无关紧要。 – Stephen 2012-03-05 19:03:51

回答

0

我已经想通了这一点

,因为我的命令接收方法虚空工作(对象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线程将被通知运行其余的接收代码..这解决了我的问题。

2

由于backgroundWorker1_ProgressChanged()运行在与创建labelRemaining控件的线程不同的线程上,因此您正在获取该错误。假设您创建的主UI线程上labelRemaining控制,你需要:

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

  • backgroundWorker1_ProgressChanged,使用调度程序作为described here

更新执行改变你labelRemaining对象在主线程: 我看到你正在使用的WinForms,而不是WPF。而不是使用分派这应该为你工作:How to update the GUI from another thread in C#?

+0

我认为你可能是正确的..因为在接收案例..从客户端接收命令的方法是在一个线程中运行,然后它在接收命令的同一个线程中调用backgroundworker.runasync()..这就是为什么我得到这个异常? – 2012-03-05 19:15:12

+0

我很确定这是为什么。否则,你不会从BackgroundWorker获取该异常。 – 2012-03-05 19:16:44

+0

问题解决.. – 2012-03-05 19:31:28

相关问题