Conmajia © 2012, 2018

Published on August 5th, 2012

Updated on February 2nd, 2019

Introduction

While working on background threads, you may encounter updating values of frontend GUI controls. Then you probably will face one particular problem: invalid operation between threads. As shown in figure 1, this issue throws an InvalidOperationException. It occurs every time when accesses properties/methods from other threads but the one which owns them.

Fig. 1 Invalid Cross-Thread Call (screenshot)

In .NET Framework, version 2.0 as I refer, every Control class contains an InvokeRequired property and an Invoke method to accomplish cross-thread operations. Some typical call code is listed below.

public void DoWork() {
if (control.InvokeRequired) {
control.Invoke(DoWork);
}
else {
// do work
}
}

My Approach

I wrote a helper class InvokeHelper which granted me the power to access assets between different threads. The class has 3 methods:

  1. Invoke() - to call methods of a control.
InvokeHelper.Invoke(<control>, "<method>"[, <param1>[,<param2>,...]]);
  1. Get() - to get properties of a control.
InvokeHelper.Get(<control>, "<property>");
  1. Set() - to set properties of a control.
InvokeHelper.Set(<control>, "<property>", <value>);

Demonstration

In the demo, I used a forever looping background thread (t) to show how the InvokeHelper helps threads to interact. Thread t updates the frontend thread (the GUI) every 500 milliseconds.

Thread t;
private void button1_Click(object sender, EventArgs e) {
if(t == null) {
t = new Thread(multithread);
t.Start();
label4.Text = string.Format("Thread state:\n{0}", t.ThreadState.ToString());
}
}
public void DoWork(string msg) {
this.label3.Text = string.Format("Invoke method: {0}", msg);
}
int count = 0;
void multithread() {
while(true) {
InvokeHelper.Set(this.label1, "Text", string.Format("Set value: {0}", count));
InvokeHelper.Set(this.label1, "Tag", count);
string value = InvokeHelper.Get(this.label1, "Tag")
.ToString();
InvokeHelper.Set(this.label2, "Text", string.Format("Get value: {0}", value));
InvokeHelper.Invoke(this, "DoWork", value);
Thread.Sleep(500);
count++;
}
}

Results shown in animated figure 2. Obviously, the frontend is not blocked despite t never stops.

Fig. 2 InvokeHelper Demonstration (animation)

Other Approaches

There is a built-in option in the VisualStudio IDE that disables the cross-thread access check: CheckForIllegalCrossThreadCalls. I found it slightly slower than my helper class. Figure 3 shows the test result.

Fig. 3 Test Result for CheckForIllegalCrossThreadCalls

The whole procedure of the test is recorded in figure 4. (The video lasts for 8'51")

Fig. 4 Test Video for CheckForIllegalCrossThreadCalls (8'51")

Appendix

Source code of the InvokeHelper is listed below. Zipped .NET project files: Download


public class InvokeHelper {
private delegate object MethodInvoker(Control control, string methodName, params object[] args);
private delegate object PropertyGetInvoker(Control control, object noncontrol, string propertyName);
private delegate void PropertySetInvoker(Control control, object noncontrol, string propertyName, object value);
private static PropertyInfo GetPropertyInfo(Control control, object noncontrol, string propertyName) {
if (control != null && !string.IsNullOrEmpty(propertyName)) {
PropertyInfo pi = null;
Type t = null;
if (noncontrol != null) t = noncontrol.GetType();
else t = control.GetType();
pi = t.GetProperty(propertyName);
if (pi == null) throw new InvalidOperationException(string.Format("Can't find property {0} in {1}.", propertyName, t.ToString()));
return pi;
} else throw new ArgumentNullException("Invalid argument.");
}
public static object Invoke(Control control, string methodName, params object[] args) {
if (control != null && !string.IsNullOrEmpty(methodName))
if (control.InvokeRequired) return control.Invoke(new MethodInvoker(Invoke), control, methodName, args);
else {
MethodInfo mi = null;
if (args != null && args.Length > 0) {
Type[] types = new Type[args.Length];
for (int i = 0; i

References

  1. Sergiu Josan, Making Controls Thread-safely, May 2009
  2. vicoB, Extension of safeInvoke, July 2010

The End. \(\Box\)

💈 A Cross-Thread Call Helper Class的更多相关文章

  1. update the UI property cross thread

    this.Invoke((MethodInvoker)delegate { txtResult.Text = sbd.ToString(); // runs on UI thread });

  2. Flink - Checkpoint

    Flink在流上最大的特点,就是引入全局snapshot,   CheckpointCoordinator 做snapshot的核心组件为, CheckpointCoordinator /** * T ...

  3. [转]How to display the data read in DataReceived event handler of serialport

    本文转自:https://stackoverflow.com/questions/11590945/how-to-display-the-data-read-in-datareceived-event ...

  4. c#子线程线程中操作窗体更新的报错

    用 在执行上传时,由于操作较长窗体界面卡住,于是用task解决 Task t1 = new Task(manage.UploadData); t1.Start(); 结果不卡了,程序也传完了,运行到更 ...

  5. 进程创建过程详解 CreateProcess

    转载请您注明出处:http://www.cnblogs.com/lsh123/p/7405796.html 0x01 CreateProcessW CreateProcess的使用有ANSI版本的Cr ...

  6. C#委托+回调详解

    今天写不完,明天会接着写的,,,, 学习C#有一段时间了,不过C#的委托+回调才这两天才会用,以前只是知道怎么用.前面的一篇文章,函数指针,其实是为这个做铺垫的,说白了委托就相当于C语言中的函数指针, ...

  7. windows中的进程和线程

    今天咱们就聊聊windows中的进程和线程 2016-09-30 在讨论windows下的进程和线程时,我们先回顾下通用操作系统的进程和线程.之所以称之为通用是因为一贯的本科或者其他教材都是这么说的: ...

  8. [MethodImpl(MethodImplOptions.Synchronized)]、lock(this)与lock(typeof(...))

    对于稍微有点经验的.NET开发人员来说,倘若被问及如何保持线程同步,我想很多人都能说好好几种.在众多的线程同步的可选方式中,加锁无疑是最为常用的.如果仅仅是基于方法级别的线程同步,使用System.R ...

  9. Xamarin.Forms客户端第一版

    Xamarin.Forms客户端第一版 作为TerminalMACS的一个子进程模块,目前完成第一版:读取展示手机基本信息.联系人信息.应用程序本地化. 功能简介 详细功能说明 关于TerminalM ...

  10. [源码解析] 深度学习流水线并行 PipeDream(5)--- 通信模块

    [源码解析] 深度学习流水线并行 PipeDream(5)--- 通信模块 目录 [源码解析] 深度学习流水线并行 PipeDream(5)--- 通信模块 0x00 摘要 0x01 前言 0x02 ...

随机推荐

  1. Mybatis问题:There is no getter for property named 'unitId' in 'class java.lang.String'

    Mybatis遇到的问题 问题: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.re ...

  2. Discuz论坛URL静态化规则urlrewrite

    http://blog.csdn.net/u014181418/article/details/53467980 1.在论坛代码目录下新建文件".htaccess" vim /us ...

  3. Servlet--Servlet接口

    servlet主要数据结构 Servlet 接口:主要定义了servlet的生命周期方法 ServletConfig接口:为servlet提供了使用容器服务的若干重要对象和方法. ServletCon ...

  4. js内置函数大全及基本使用方法(一)

    一,常规函数 alert函数:显示一个警告对话框,包括一个OK按钮. 语法:alert("hello world"); confirm函数:显示一个确认对话框,包括OK.Cance ...

  5. C# Ioc 接口注册实例以及注入MVC Controller

    当弄一个小程序时,就忽略了使用Ioc这种手段,作为一个帅气程序员,代码规范,你懂的~,废话不多说,快速搭建一个Ioc接口实例以及直接注入到 MVC Controller 构造函数中如下: MVC in ...

  6. ABP官方文档翻译 2.3 缓存

    缓存 介绍 ICacheManager 警告:GetCache方法 ICache ITypedCache 配置 实体缓存 实体缓存如何工作 Redis缓存集成 介绍 ABP为缓存提供了一个抽象接口,它 ...

  7. 什么是SSL

    什么是SSL 简单来说,在我们使用的浏览器中都默认信任着全世界多个最权威的CA机构(证书颁发机构),如下图: 上图中,受信任的根证书颁发机构列表里的都是我们浏览器中默认信任的CA机构,我们只需要向他们 ...

  8. 《Thinking in Java》学习笔记(一)

    服务器端的编程可以参考另一本书<企业Java编程>(Thinking in Enterprise Java). 1.基本类型 基本型别 大小 最小值 最大值  默认值 boolean -- ...

  9. Spring整合JDBC及事务处理

    1.Spring整合JDBC DAO是数据访问对象(data access object)的简写.接口是实现松耦合的关键,Spring也鼓励使用接口,但不是强制的. 捕获异常时希望能尝试从异常状态中恢 ...

  10. Cannot read property 'component' of undefined 即vue-router 0.x转化为2.x

    原文链接:http://blog.csdn.net/m0_37754657/article/details/71269988 由于vue版本为1.0,没有一些vue-router指令:因而需要vue- ...