我意识到我无法从 BackgroundWorker 的 DoWork 事件处理程序访问表单控件。(如果我尝试这样做,我会得到一个异常,正如预期的那样)。
但是,是否允许我访问表单上存在的其他(自定义)对象?
例如,我创建了一个“设置”类并在我的表单中对其进行了实例化,我似乎能够读取和写入它的属性。
这只是运气吗?
如果我有一个静态类怎么办?我可以安全地访问它吗?
我意识到我无法从 BackgroundWorker 的 DoWork 事件处理程序访问表单控件。(如果我尝试这样做,我会得到一个异常,正如预期的那样)。
但是,是否允许我访问表单上存在的其他(自定义)对象?
例如,我创建了一个“设置”类并在我的表单中对其进行了实例化,我似乎能够读取和写入它的属性。
这只是运气吗?
如果我有一个静态类怎么办?我可以安全地访问它吗?
@英格拉姆:
您已经掌握了要点 - CrossThreadCalls 只是 MS 放入 .NET Framework 中的一个很好的功能,用于防止“愚蠢”类型的并行编程错误。它可以被覆盖,正如我猜你已经发现的那样,通过在类上设置“AllowCrossThreadCalls”属性(而不是在类的实例上,例如设置 Label.AllowCrossThreadCalls 而不是 lblMyLabel.AllowCrossThreadCalls)。
但更重要的是,您对使用某种锁定机制的需求是正确的。每当您有多个执行线程(无论是线程、进程还是其他)时,您都需要确保当您有一个线程读取/写入变量时,您可能不希望其他线程插入并更改该值第一根线的脚。
.NET Framework 实际上提供了几种其他机制,根据具体情况,这些机制可能比锁定代码更有用。第一种是使用Monitor类,它具有锁定特定对象的效果。当您使用它时,其他线程可以继续执行,只要它们不尝试锁定同一个对象。另一个非常有用且常见的并行编程思想是Mutex(或Semaphore)。互斥锁基本上就像你的线程之间的夺旗游戏。如果一个线程抓住了标志,那么在第一个线程丢弃它之前,没有其他线程可以抓住它。(信号量与互斥量类似,只是在游戏中可以有多个标志。)
Obviously, none of these concepts will work in every particular problem - but having a few more tools to help you out might come in handy some day :)
您应该通过ProgressChanged
andRunWorkerCompleted
事件与用户界面进行通信(而不是您提到的 DoWork() 方法)。
原则上,您可以调用 IsInvokeRequired,但BackgroundWorker
该类的设计者创建ProgressChanged
回调事件是为了更新 UI 元素。
[注意:BackgroundWorker 事件不会跨 AppDomain 边界封送。不要使用 BackgroundWorker 组件在多个 AppDomain 中执行多线程操作。]
MSDN参考。
好的,我对此做了更多的研究,我想有一个答案。(让投票决定我是否正确!)
答案是......您可以访问范围内的任何自定义对象,但是您的访问将不是线程安全的。
为确保它是线程安全的,您可能应该使用lock。lock 关键字可防止多个线程执行一段特定的代码。(以实际正确使用为准!)
当您尝试访问控件时发生的跨线程异常是一种专为控件设计的安全机制。(让用户进行线程安全调用比将控件本身设计为线程安全的更容易并且可能更有效)。
您不能从另一个线程访问在一个线程中创建的控件。您可以使用您提到的 Settings 类,也可以使用 InvokeRequired 属性和 Invoke 控制方法。
我建议您查看这些页面上的示例:
http://msdn.microsoft.com/en-us/library/ms171728.aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx