`

多线程下WinForm开发应该注意哪些问题?

阅读更多

昨日,与一同事一起在修一个多线程下使用我们的控件产品的Bug。现将相关的经验发布在这里。


1. 标准WinForm控件不支持多线程访问

这一点,其实是Windows的机制。.NET 中每一个Control其实都是一个Window,使用这些Window,原则上都应该在创建这个Window的线程中。否则,会产生异常。这一点,似乎Windows也没有强制约束。某些操作可能会扔异常,而有些情况下却不会。比如:访问这个Window的某些属性。

因此,.NET在Control上暴露了Invork方法,以实现将操作发送到Control所属的线程中执行。细节,可以参考我以前的一篇帖子。

这一点,已经是标准做法。所以不能称之为Bug。

现在我们来看一下出现了什么Bug。用户的应用程序中,某些时候需要启动一个新的线程,在这个线程中构造并显示一个Form,其中包含我们的控件。当用户启动后,发现我们的产品不能够正确地显示。

什么原因呢?


2. 静态成员是元凶

根据经验,这种情况下的问题一般都出在静态成员上。我们在开发中,经常为了优化性能,而将一些对象缓存在静态成员中。如果我们将一个包含Window的对象缓存在静态对象中,对它的调用就可能会产生异常。

大家都知道,静态成员是属于整个AppDomain的,也就是说,所有的线程在共享同一个静态对象。当另外一个线程调用静态对象上的方法时,根据前面的规则(WinForm控件不支持多线程访问),异常产生了。

呵呵,这一点,是我在以前修Bug中的经验。但是,昨天似乎并不灵验。整个出现异常的部分没有发现缓存静态的Window对象。

经验告诉我,肯定是静态成员惹得祸。先看出问题的代码,发现这里缓存了一个静态的Bitmap。

难道是,这个Bitmap不允许跨线程访问?对这个Bitmap对象进行了锁(Lock)操作后,发现问题解决。于是得出了下面的经验。


3. 某些GDI对象也不允许跨线程访问

GDI对象(包括GDI+对象)都是有Handle的。可能在某些情况下,微软也不保证跨线程访问的可靠性。从昨天的调试结果来看,这些对象应该是不允许多个线程并发访问。这一点并没有太多的跟踪和调试,如果你有兴趣,可以尝试的再跟一下。

通过对这些对象加锁,避免并发访问,似乎问题已经解决。但是因为这一部分被使用的非常频繁(否则我们也不加Cache了),加锁后,发现对控件的性能产生很大的影响。看来仅仅加锁是不能解决所有问题的。

于是,昨天从Winking那里学了一着。


4. System.ThreadStaticAttribute

这个属性标示一个静态对象在每个线程中是独立的。因此,我们只要在这些缓存字段上加上这个属性。哈哈,问题解决。喔,看起来解决的太轻松了。先别急,现实往往比想象中残酷。


5. 静态对象的初始化的问题

我们一般会使用两种方式初始化静态对象。静态构造函数 和 第一次访问时。(我们经常会在静态对象的声明后面直接进行初始化,这种情况其实也是通过静态构造函数进行初始化的。只是编译器帮助我们将这些代码移动到了静态构造函数里面。因此,这里不单独讨论。)

如果我们将静态字段标记为线程唯一的,静态构造函数就不能够正确地初始化这个字段了。因为,静态构造函数只被调用一次。(它没有办法标记为线程唯一的:))

于是,这里就需要使用延迟构建模式。我们需要将这些静态成员声明为属性,在其Get函数中判断对象是否为空(或默认值,值类型)。从而确定是否需要构造缓存对象。 


6. 总结

呵呵,至此,所有的问题都解决了,Bug也已经修复。总体来说,静态对象始终是一个不安全因素。在目前我负责的项目中,我们是尽量避免使用静态成员。如果需要缓存对象,我们也会将这些缓存对象放在一个特定的池中。确保缓存对象是面向特定实例的而不是全局的。避免出现上面的问题。

相关文章:.NET下跨线程访问Control。
http://www.cnblogs.com/Cajon/archive/2006/06/23/433642.html

 

 

转自 cajon

分享到:
评论

相关推荐

    C# Winform 多线程下载

    在C# Winform应用中实现多线程下载是一项常见的任务,尤其在处理大文件或需要提高下载速度的情况下。本文将详细讲解如何利用C#的多线程技术来创建一个Winform应用程序,实现高效的文件下载功能。 首先,我们需要...

    C#多线程调用Winform窗体[文].pdf

    综上所述,本文档深入探讨了在多线程环境下,如何通过ISynchronizeInvoke接口和Winform的委托来安全地进行UI操作,这是在C#中开发Winform应用程序时经常会遇到且需要妥善解决的问题。通过理解和运用这些知识点,...

    多线程定时器Web和Winform双版本

    在IT领域,多线程定时器是一个非常实用的工具,特别是在开发Web应用程序和Windows桌面应用(Winform)时。这个工具允许程序员在多个线程环境中设置定时任务,从而实现后台处理、定期检查更新或者执行一系列间隔操作...

    WinCe多线程访问winform中控件

    在Windows CE(WinCe)平台上开发应用程序时,经常会遇到多线程环境下的UI交互问题。标题和描述提及的“WinCe多线程访问winform中控件”是一个关键的编程挑战,因为不正确的操作可能会导致异常,如线程竞态条件、...

    winform多线程计算调用js

    在多线程环境中,需要注意线程同步问题,因为WebBrowser控件的大部分操作是线程不安全的,必须在UI线程中进行。当我们从后台线程调用`InvokeScript`后,需要确保结果的处理或者对WebBrowser控件的其他修改回到UI线程...

    WinForm自定义多线程

    在Windows Forms(WinForm)应用开发中,多线程技术是一项关键技能,它允许应用程序同时执行多个任务,提高程序响应速度并优化资源管理。本文将深入探讨如何在WinForm应用中自定义多线程,以实现高效且用户友好的...

    C# Winform 实现Http多线程下载

    在C#编程中,实现Http多线程下载是一项常见的任务,尤其在处理大文件或需要提高下载速度的情况下。本文将详细讲解如何利用C# Winform框架实现这一功能,并结合多线程技术提升下载效率。 首先,我们需要理解Http协议...

    C#WinForm,多线程快速刷新界面。

    总之,C# WinForm中利用多线程技术可以有效地解决界面快速刷新问题。通过合理地使用`Task`、`async/await`以及线程同步方法,我们可以创建出流畅、响应迅速的用户界面。同时,开发者还应关注线程间的通信和数据同步...

    Winform实现多线程异步更新UI(进度及状态信息)

    为了解决这个问题,开发者通常会采用多线程技术,将耗时任务放在后台线程执行,同时确保UI线程能及时更新进度和状态信息。本文将详细讲解如何在WinForm应用中实现多线程异步更新UI。 1. **线程基础知识**:在...

    C#下WINFORM和WINCE多线程编程

    在C#编程环境中,开发Windows桌面应用程序(WinForms)或嵌入式系统应用程序(Windows CE,简称WINCE)时,多线程技术是一项至关重要的技能。多线程允许程序同时执行多个任务,提高应用程序的响应性和效率。下面将...

    C# Winform线程创建子窗体

    在C# Winform开发中,多线程技术是不可或缺的一部分,尤其当涉及到用户界面(UI)的异步操作时。线程允许程序同时执行多个任务,提高应用的响应性和效率。本话题将深入探讨如何利用线程来延迟创建子窗体,并且如何安全...

    winform_datagridview多线程出现红叉解决方案

    在Windows Forms(WinForm)应用程序中,`DataGridView`控件是一种常用的数据展示工具,它可以方便地显示和编辑表格数据。...在编写代码时,时刻注意线程安全,是开发高效、可靠的多线程WinForm应用的关键。

    C# WinForm多线程开发复习进程.pdf

    C# WinForm 多线程开发复习进程 ...C# WinForm 多线程开发是一种复杂的编程技术,需要了解多线程机制、线程间的同步和通信、避免死锁和资源竞争等问题。但是,如果正确使用多线程技术,可以提高程序的效率和性能。

    winForm 多线程操作UI

    在Windows Forms(winForm)应用开发中,多线程操作UI是提高应用程序性能和响应性的重要技术。在传统的单线程环境中,UI更新和后台任务往往在同一线程中执行,导致用户界面在处理耗时任务时可能出现卡顿或无响应。...

    C#WinForm多线程开发[参考].pdf

    C# WinForm多线程开发是软件开发中一个关键的领域,尤其是在处理耗时操作或者需要并发执行任务的应用程序中。本文将深入探讨C#中的多线程概念,以及如何在WinForm应用程序中安全地使用线程。 首先,理解线程和进程...

    SUM分页控件(支持WinForm多线程)源码 SUMPagingControls.rar

    SUM分页控件(支持WinForm多线程)源码 源码描述: 一、源码特点 本软件是一个WinForm分页控件演示程序。其中分页控件简洁高效,支持多线程的跨线程安全访问,是开发数据展示软件的优秀分页控件。 二、功能介绍 1...

    委托 线程 访问WINFORM控件

    5. **异常处理**: 虽然委托提供了安全访问UI控件的方式,但在多线程环境下,仍需注意同步问题和可能的线程冲突。合理使用`lock`关键字或其他同步机制,避免资源竞争。 6. **控制台应用程序中的WinForm控件访问**: ...

    .NET多线程实例

    在多线程场景下,每个部分可以由不同的线程处理,但同样需要注意线程同步以防止UI更新问题。 总之,这个.NET 2.0的多线程实例涵盖了多线程的创建与管理、线程同步、UI更新、文件系统操作、异步编程等多个核心知识点...

    winform多线程更新控件

    在Windows Forms(Winform)应用程序开发中,多线程技术是一项关键技能,特别是在处理耗时操作时,如大数据处理、网络通信或者长时间计算等。这些操作如果在主线程上执行,将导致用户界面(UI)无响应,影响用户体验...

    C# winform 防止界面卡住 线程 委托

    在C# WinForm开发中,我们常常遇到这样一个问题:当执行耗时操作(如大量数据处理、网络请求等)时,界面会变得无响应,即“卡住”。为了解决这个问题,我们需要理解并运用线程和委托的概念。本文将详细阐述如何在C#...

Global site tag (gtag.js) - Google Analytics