后台工作者和交叉线程问题

问题描述

| 我有一个运行良好的Winforms应用程序。在使用串行数据处理设备期间,使用BackgroundWorkerThread管理GUI可用性。 工作正常。 现在,我正在添加一个方法,并以其他形式复制我所做的事情。但是我遇到了跨线程异常。 我这样声明我的BWT:
BackgroundWorker bw = new BackgroundWorker();
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += DownloadGpsDataFromDevice;
            bw.WorkerReportsProgress = true;
            bw.RunWorkerAsync();
然后,我有一个像这样的方法,它可以完成后台工作:
private void DownloadGpsDataFromDevice(object sender,DoWorkEventArgs e)
{
    _performScreenUpdate = true;
    tsstatus.Text = \"Downloading GPS Data...\";
    Invalidate();
    Refresh();


    Common.WriteLog(\"Extracting raw GPS data. Sending LL.\");

    ReplyString raw = DeviceServices.ExecuteCommand(\"$LL\");
DeviceServices.ExecuteCommand(\“ $ LL \”);是可以完成工作的位,但是我在上一行记录到文本文件的上一行出现了异常。现在,这让您担心-写入文件。但是,我在另一个BWT中做了数千次。 我使编写线程安全。这是我的Common.WriteLog方法
public static void WriteLog(string input)
{
    lock (_lockObject)
    {
        WriteLogThreadSafe(input);
    }
}

private static void WriteLogThreadSafe(string input)
{
    Directory.CreateDirectory(LogFilePath);
    StreamWriter w = File.AppendText(LogFilePath + @\"\\\" + LogFileName);
    try
    {
        w.WriteLine(string.Format(\"{0}\\t{1}\",DateTime.Now,input));
    }
    catch (Exception e)
    {
        System.Console.WriteLine(\"Error writing to log file!\");
        System.Console.WriteLine(\"Tried to write: [\" + input + \"]\");
        System.Console.WriteLine(\"Failed with error: [\" + e.Message + \"]\");
    }
    finally
    {
        w.Close();
    }

}
这已经工作了很长时间了。我不相信错误在那里。我想我可能只是在通话中遗漏了一些东西?     

解决方法

        您无法从BackgroundWorker线程更改UI元素。您必须通过调用
Invoke()
编组回UI线程。 尝试这个
private void DownloadGpsDataFromDevice(object sender,DoWorkEventArgs e)
{
    _performScreenUpdate = true;
    Invoke((MethodInvoker)(() => {
             tsStatus.Text = \"Downloading GPS Data...\";
             Invalidate();
             Refresh();
     });
     ...
    ,        问题是您正在从非UI线程更新UI元素: 这些行不应在ѭ5内
tsStatus.Text = \"Downloading GPS Data...\";
Invalidate();
Refresh();
要利用
BackgroundWorker
运行方法method8ѭ。专门用于此目的的
ProgressChanged
处理程序中的更新UI。
void bw_ProgressChanged(object sender,ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage = 0)
    {
        tsStatus.Text = \"Downloading GPS Data...\";
        Invalidate();
        Refresh();
    }
}
    ,        某些实例不能或不应该由多个线程访问。您有两个选择来保护数据免受跨线程异常的影响。 您可以使用多个锁从多个线程访问对象时将其锁定: 对象储物柜= new object(); SomeObject MyObject = new SomeObject();
private void FromMultipleThread()
{
    lock(locker)
    {
        MyObject = OtherObject;
    }
}
第二种选择是使用ManualResetEvent锁定线程。这非常简单,您只需要从ManualResetEvent调用WaitOne()即可锁定线程,而另一个线程则可以访问“跨线程”对象。 在您的情况下,您想从backgroundWorker的reportProgress更改UI。 reportProgress将返回到初始线程,然后您可以修改UI。     ,        您确定那是对的吗?我认为您不应该能够在工作程序中更新ui。尝试注释掉gui更新并清理并构建您的解决方案,以查看日志记录是否确实是问题所在。要更新ui,请设置WorkerReportsProgress并为此创建事件处理程序,以更新ui并报告worker中的进度。     

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...