如何解决后台工作者和交叉线程问题
| 我有一个运行良好的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中的进度。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。