zoukankan      html  css  js  c++  java
  • 跨线程访问Windows窗体控件

    介绍 web上有许多文

      

    章都是关于如何正确处理多个应用程序线程和跨这些线程访问数据的,但本文的目的是消除许多其他文章中出现的模糊性或不准确信息。 什么是多线程? 许多程序员和非程序员都对多任务操作系统如何能够同时执行这么多任务感到困惑。我认为需要注意的是,事实上,没有处理器能够“同时做两件事”。实现“并行执行”的方式是通过给每个应用程序少量的处理时间,允许每个应用程序一次处理几行代码,给人一种它们同时运行的感觉。在编程术语中,这是通过“多线程”方法实现的。在这个上下文中,每个“线程”是一组单独的指令,要并行处理。理解多线程或“并行”处理过程中处理器内部真正发生了什么是很重要的。 多线程是如何工作的? 举个例子,假设我们有一个应用程序,它需要分析一张照片,并尝试找出看起来像是人脸的东西。这将需要一套非常复杂的数学算法来针对图像中的每个像素或彩色点运行。对于较大的图像,这可能需要很长时间。 大多数执行某种数据操作的代码语句都是“阻塞”的。也就是说,它们在完成执行之前阻止下一行代码的执行。这被称为“同步执行”,因为每一行代码都是按顺序执行的。 在多线程环境中,现有线程可以派生子线程,使父线程能够在子线程执行其工作时继续执行。创建一个子线程并立即返回执行下一行代码的语句称为“非阻塞”。这被称为“异步执行”,因为多行代码似乎同时执行。 让我们打个比方。想象你的计算机处理器是一条高速公路。当只有一条车道时,一次只能有一辆车行驶。如果一辆车开得很慢,那么后面的每一辆车都必须慢下来等待它。现在,假设应用程序中的每个线程都是一个额外的车道。现在,这些汽车可以并排行驶,有些甚至可以跑得更快。现在想想高速公路是由代码行构建的,汽车代表代码的执行。 当应用程序运行多个线程时,需要考虑很多事情,包括数据同步和稳定性。您不会希望线程A给一个变量赋值,然后线程B在线程A能够使用它之前更改该值。这就是所谓的“竞争条件”(实际上,不仅仅是因为我使用的是汽车的类比)。包含防止这些竞态条件的代码的类被认为是“线程安全的”。. net框架中的许多类都是线程安全的,但也有许多不是。 关于多线程,最常被误用的。net类型是System.Windows。表单控件。这些类不是线程安全的,但是您经常会发现代码跨线程边界不正确地处理这些对象。回到我们的高速公路类比,线程边界将是定义每个车道的线。如果一辆车没有采取适当的步骤,没有使用转向灯,也没有确保车道畅通,就跳到了另一条车道上……崩溃! 非线程安全的类型就像只有一个前挡风玻璃和没有侧挡风玻璃的汽车。他们不可能看到周围的其他车辆在做什么,所以其他车辆如果想要换道,就必须确保遵循正确的程序。 换车道 现在让我们更具体地了解一下Windows窗体控件…所有Windows窗体控件都继承了一个名为System.Windows.Forms.Control的基类。很明显的。这个“控件”类公开了一个名为“InvokeRequired”的公共布尔属性。这个属性让您知道,如果控件返回一个假值,从当前线程访问该控件是否可以。 基本上,这个属性会告诉您是否有必要在最初创建控件的线程上调用所需的操作,如果子线程试图访问在主线程上创建的控件,则会出现这种情况,反之亦然。 不要害怕 “调用”是一个术语,用来描述一个线程请求另一个线程执行一段代码。这是通过使用“委托”来完成的。 委托是在对象之间传递对方法的引用的一种类型安全的方式。下面是一个基本的委托定义: 隐藏,复制Code

    delegate void ChangeMyTextDelegate(Control ctrl, string text);

    它定义了对返回类型为“void”的方法的引用,并接受两个参数:Control和String。看看下面的我尝试更新指定控件的文本的方法。 隐藏,复制Code

    public static void ChangeMyText(Control ctrl, string text);
    {
        ctrl.Text = text;
    }

    假设调用此方法的线程与创建控件的线程是同一线程,这样做就很好了。如果不这样做,我们就会面临汽车相撞的危险。 为了解决这个问题,我们使用控件的“InvokeRequired”属性和我们刚才定义的委托。结果代码如下: 隐藏,复制Code

    delegate void ChangeMyTextDelegate(Control ctrl, string text);
    public static void ChangeMyText(Control ctrl, string text)
    {
        if (ctrl.InvokeRequired)
        {
            ChangeMyTextDelegate del = new ChangeMyTextDelegate(ChangeMyText);
            ctrl.Invoke(del, ctrl, text)
        }
        else
        {
            ctrl.Text = text;
        }
    }

    第一行声明了委托的定义。与之前一样,我们将它定义为一个返回void并接受两个参数的方法。然后是我们实际的方法。这个方法做的第一件事是检查我们是否在正确的线程上访问作为第一个参数传递的控件对象'ctrl'。如果需要调用,我们将创建委托的一个新实例,并将其指向“ChangeMyText”方法。然后,通过传递委托和委托所需的参数,让控件为我们执行代码。您现在可能已经注意到,委托的签名与它所表示的方法的签名相匹配。委托引用方法时必须始终为真。 在控件为我们(在它自己的线程上)执行这个方法后,"InvokeRequired"将计算为false,允许'else'块执行并将控件的'Text'属性设置为在'Text'参数中指定的字符串。 哪些语句是“阻塞的”? 通常,您编写的每条语句都将被阻塞。这条规则的例外是,如果您调用以单词“Begin”开头的方法。这是一个识别非阻塞方法调用的典型编码标准。在编写自己的多线程代码时,这是一个很好的语法规则,尤其是在编写可重用类库时,因为如果您将DLL交给其他人使用,它将有助于维护一致性。除了我们上面使用的“Invoke”方法之外,控件类还公开了一个“BeginInvoke”方法,它做的事情完全相同,只是它是一个非阻塞语句。 我们将何去何从? 请查看附加的文件“CrossThreadUI”。它是我所编写的更大的类库中的一个文件。它不仅包含上面的例子几乎相同的方法(称为“SetText”。cs文件),但它也暴露了许多其他静态方法使您能够设置任何属性的任何类型的控制对象,甚至和一些使用反射来验证对象和参数类型。它是一个有用的助手类,也是体验一些多线程Windows窗体控制访问的好方法。 的兴趣点 特别要确保在源代码中检出InvokePropertyMethod。它将对所提供的实例使用反射来查找该实例的指定属性值,并允许您执行该属性类型的方法,同时保持线程安全。源代码中包含几个方法,允许您使用控件属性的成员。 这里需要注意一件有趣的事情,我在编写这段代码时发现:所有这些源代码都可以很容易地移植到VB中。除了ShowMessageBox方法之外,只需对语法进行必要的更改。这是因为,而VB。NET不支持与c#相同的接口,所以System.Windows。窗体对象在VB。NET不像在c#中那样继承IWin32Window接口。如果你试图重写这个代码到VB。NET时,需要将此方法的第一个参数的类型更改为System.Windows。表单以使代码正常工作。它将使用当前接口名称进行编译,但是如果您试图传递类型为System.Windows的实例,它将抛出一个异常。形式。 历史 本文最初是由我于2009年4月23日在CSharpCorner上发表的。我确实意识到,关于找脸是一个耗时的过程的评论在这一点上可能是不正确的。:) 本文转载于:http://www.diyabc.com/frontweb/news272.html

  • 相关阅读:
    部署webapp到web容器的三种方式(这里的web容器Tomcat)
    jquery1.8.3文档的一些问题(可能是我理解错了,不喜勿喷)
    JQuery异步请求之省略dataType的设置
    Tomcat启动一闪而过的问题(我是windows系统,所以查看的是.bat的文件)
    tomcat控制台乱码问题
    IDEA常用的快捷键和代码模板
    ajax返回问题
    php大文件下载问题
    微信企业付款到银行卡
    支付宝单笔转账支付功能
  • 原文地址:https://www.cnblogs.com/Dincat/p/13437346.html
Copyright © 2011-2022 走看看