Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 后台工作程序和跨线程问题_C#_Multithreading_Backgroundworker - Fatal编程技术网

C# 后台工作程序和跨线程问题

C# 后台工作程序和跨线程问题,c#,multithreading,backgroundworker,C#,Multithreading,Backgroundworker,我有一个Winforms应用程序,运行良好。。使用BackgroundWorkerThread管理设备串行数据处理期间的GUI可用性 很好用 现在,我正在添加一个新方法,并复制我在其他形式中所做的。但我得到了一个交叉线程异常 我声明我的BWT如下: BackgroundWorker bw = new BackgroundWorker(); bw.WorkerSupportsCancellation = true; bw.DoWork += Down

我有一个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元素:

这些行不应位于从设备下载的GPSDataFromDevice中

tsStatus.Text = "Downloading GPS Data...";
Invalidate();
Refresh();
利用
BackgroundWorker
run方法
bw.ReportProgress(0)。更新
ProgressChanged
处理程序中的UI,该处理程序专门为此目的而设计

void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    if (e.ProgressPercentage = 0)
    {
        tsStatus.Text = "Downloading GPS Data...";
        Invalidate();
        Refresh();
    }
}

某些实例不能或不应该被多个线程访问。有两个选项可以保护数据不受跨线程异常的影响

使用锁从多个线程访问对象时,可以锁定对象:

对象锁定器=新对象()

SomeObject MyObject=新建SomeObject()

第二个选项是使用ManualResetEvent锁定螺纹。这非常简单,您只需从ManualResetEvent调用WaitOne()即可锁定您的线程,而另一个线程将访问您的“交叉线程”对象


在您的情况下,您可能希望从backgroundWorker的reportProgress更改UI。reportProgress将返回到初始线程,然后您可以修改UI。

您确定这是正确的行吗?我认为您不应该能够更新worker中的ui。尝试注释gui更新并清理并构建您的解决方案,看看日志记录是否真的是问题所在。要更新ui,请设置WorkerReportsProgress并为此创建一个事件处理程序,以更新ui并报告worker中的进度。

这些行似乎工作正常。。。还是我犯了错误?它在Common.WriteLog(“提取原始GPS数据,发送LL”)上崩溃;等待看来你是对的!应用程序在日志行崩溃了,但是当我把你提到的那些行注释掉时。。。它起作用了。奇怪的是,它在日志行上崩溃了。谢谢@cdotlister—如果不使用
ProgressChanged
RunWorkerCompleted
事件,则不需要使用。这两个事件是
BackgroundWorker
的全部要点。这些事件总是在UI线程中触发。这些行似乎工作正常。。。还是我犯了错误?它在Common.WriteLog(“提取原始GPS数据,发送LL”)上崩溃;等待看来你是对的!应用程序在日志行崩溃了,但是当我把你提到的那些行注释掉时。。。它起作用了。奇怪的是,它在日志行上崩溃了。谢谢@cdotlister
WriteLog()
对我来说似乎没问题,不应该导致跨线程异常。在那种情况下我不确定。
private void FromMultipleThread()
{
    lock(locker)
    {
        MyObject = OtherObject;
    }
}