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\)

💈 线程间互访助手类 (EN)的更多相关文章

  1. Java:多线程,使用同步锁(Lock)时利用Condition类实现线程间通信

    如果程序不使用synchronized关键字来保证同步,而是直接使用Lock对象来保证同步,则系统中不存在隐式的同步监视器,也就不能用wait().notify().notifyAll()方法进行线程 ...

  2. 并发工具类(四)线程间的交换数据 Exchanger

    前言   JDK中为了处理线程之间的同步问题,除了提供锁机制之外,还提供了几个非常有用的并发工具类:CountDownLatch.CyclicBarrier.Semphore.Exchanger.Ph ...

  3. Java并发工具类之线程间数据交换工具Exchanger

    Exchanger是一个用于线程间协做的工具类,主要用于线程间的数据交换.它提供了一个同步点,在这个同步点,两个线程可以彼此交换数据.两个线程通过exchange方法交换数据,如果一个线程执行exch ...

  4. Java并发工具类(四):线程间交换数据的Exchanger

    简介 Exchanger(交换者)是一个用于线程间协作的工具类.Exchanger用于进行线程间的数据交换.它提供一个同步点,在这个同步点两个线程可以交换彼此的数据.这两个线程通过exchange方法 ...

  5. Object类中wait带参方法和notifyAll方法和线程间通信

    notifyAll方法: 进入到Timed_Waiting(计时等待)状态有两种方式: 1.sleep(long m)方法,在毫秒值结束之后,线程睡醒,进入到Runnable或BLocked状态 2. ...

  6. Object类中wait代餐方法和notifyAll方法和线程间通信

    Object类中wait代餐方法和notifyAll方法 package com.yang.Test.ThreadStudy; import lombok.SneakyThrows; /** * 进入 ...

  7. Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案

    本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调 ...

  8. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  9. 线程间通信 GET POST

    线程间通信有三种方法:NSThread   GCD  NSOperation       进程:操作系统里面每一个app就是一个进程. 一个进程里面可以包含多个线程,并且我们每一个app里面有且仅有一 ...

随机推荐

  1. iOS 8 中如何集成 Touch ID 功能

    2013年9月,苹果为当时发布的最新iPhone产品配备了一系列硬件升级方案.在iPhone 5s当中,最具创新特性的机制无疑要数围绕Home按钮设计的超薄金属圈,也就是被称为Touch ID的指纹传 ...

  2. React从入门到放弃之前奏(5):ReactRouter4

    概念 安装:npm i -S react-router react-router-dom GitHub:ReactTraining/react-router React Router中有三种类型的组件 ...

  3. es6学习笔记-proxy对象

    前提摘要 尤大大的vue3.0即将到来,虽然学不动了,但是还要学的啊,据说vue3.0是基于proxy来进行对值进行拦截并操作,所以es6的proxy也是要学习一下的. 一 什么是proxy Prox ...

  4. 性能超前,详解腾讯云新一代Redis缓存数据库

    背景 当前内存数据库发展迅速,用户对于存储系统的要求也越来越高,为了满足各类业务场景的需要,腾讯云设计了新一代的内存数据库,不但保留了原来系统的高性能,高可用等特性,同时还兼容了当前流行的Redis原 ...

  5. 微信小程序之表单验证

    表单验证 何为表单验证呢? 百度百科给出的回答是这样的: 表单验证是javascript中的高级选项之一.JavaScript 可用来在数据被送往服务器前对 HTML 表单中的这些输入数据进行验证 [ ...

  6. Java安全(权限)框架 - Shiro 功能讲解 架构分析

    Java安全(权限)框架 - Shiro 功能讲解 架构分析 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 简述Shiro Shiro出自公司Apache(阿帕奇),是java的一 ...

  7. 请给你的短信验证码接口加上SSL双向验证

    序言 去年年底闲来几天,有位同事专门在网上找一些注册型的app和网站,研究其短信接口是否安全,半天下来找到30来家,一些短信接口由于分析难度原因,没有继续深入,但差不多挖掘到20来个,可以肆意被调用, ...

  8. 卷积神经网络之AlexNet

    由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注. 知道2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超第二名的成绩夺冠,卷 ...

  9. SQLSERVER数据库死锁与优化杂谈

    死锁杂谈 当数据库死锁时,SqlServer会释放一个优先级较低的锁,让另一个事务运行:所以,即时去捕捉数据库死锁,是挺不容易的. 如果,数据库死锁比较长时间,那么死锁是可以被捕捉的. 可以用SqlS ...

  10. 第14章 纪元时间转换 - IdentityModel 中文文档(v1.0.0)

    JWT令牌使用所谓的Epoch或Unix时间来表示日期/时间. IdentityModel包含用于DateTime和DateTimeOffset转换到/来自Unix时间的扩展方法: var dt = ...