后台工作者和跨线程问题
我有一个运行良好的 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();
}
}
这已经工作了很长时间。我不相信错误在那里。我想我可能只是在通话中漏掉了一些东西?
I have a Winforms application which is working fine.. using a BackgroundWorkerThread to manage GUI usability during processing of serial data to a device.
It's working fine.
Now, I am adding a new method, and copying what I did in other forms. But I am getting a cross thread exception.
I declare my BWT like this:
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerSupportsCancellation = true;
bw.DoWork += DownloadGpsDataFromDevice;
bw.WorkerReportsProgress = true;
bw.RunWorkerAsync();
I then have a method delared like this, which does the background work:
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");
The DeviceServices.ExecuteCommand("$LL"); is the bit that does the work, but I am getting the exception on the previous line, where I log to a text file. Now, that makes you worry - writing to a file. However, I have done this thousands of times in another BWT.
I made the writing thread safe. Here this my Common.WriteLog method:
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();
}
}
This have been working for ages. I don't believe the error is there. I think I am just missing something on the call maybe?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您无法从BackgroundWorker 线程更改UI 元素。您必须通过调用
Invoke()
编组回 UI 线程。试试这个
You cannot change UI elements from BackgroundWorker thread. You'll have to marshall back to UI thread by calling
Invoke()
.Try this
问题是您正在从非 UI 线程更新 UI 元素:
这些行不应位于
DownloadGpsDataFromDevice
内部要利用
BackgroundWorker
运行方法bw.ReportProgress (0);
。在ProgressChanged
处理程序中更新 UI,该处理程序是专门为此目的而设计的。The issue is that you are updating UI elements from non-UI thread:
Those lines should not be inside of
DownloadGpsDataFromDevice
To take advantage of
BackgroundWorker
run methodbw.ReportProgress(0);
. Update UI inProgressChanged
handler, which was specifically designed for this purpose.某些实例不能或不应该由多个线程访问。您有两种选择来保护数据免受跨线程异常的影响。
当您从多个线程访问对象时,可以使用锁来锁定对象:
object locker = new object();
SomeObject MyObject = new SomeObject();
您的第二个选择是使用 ManualResetEvent 锁定您的线程。这非常简单,您只需从 ManualResetEvent 调用 WaitOne() 即可锁定您的线程,同时其他线程访问您的“跨线程”对象。
在您的情况下,您可能希望从backgroundWorker 的reportProgress 更改您的UI。 reportProgress 将返回到初始线程,然后您可以修改您的 UI。
Some instances can't or should not be accessed by multiple threads. You have two options to protect your data from cross thread exceptions.
You can lock your object when you access it from multiple threads with a lock:
object locker = new object();
SomeObject MyObject = new SomeObject();
Your second option is to lock your thread with a ManualResetEvent. It is very simple, you only have to call WaitOne() from you ManualResetEvent to lock your thread while an other thread access your "cross threaded" Object.
In your case, you would want to change your UI from the reportProgress of your backgroundWorker. The reportProgress will come back to the initial thread, then you can modify your UI.
您确定这是正确的路线吗?我认为您不应该能够更新工作人员中的用户界面。尝试注释掉 gui 更新并清理并构建您的解决方案,看看日志记录是否确实是问题所在。要更新 ui,请设置 WorkerReportsProgress 并为其创建一个事件处理程序,以更新 ui 并报告工作线程中的进度。
Are you sure that is the right line? I don't think you should be able to update the ui in your worker. Try commenting out the gui update and clean and build your solution to see if the logging is really the problem. To update the ui, set WorkerReportsProgress and create an event handler for that to update the ui and report progress in the worker.