http://www.cnblogs.com/Charltsing/p/publisher.html

最近测试task并发任务的效率与线程池的区别,发现了另外一个问题。task建立任务的速度很快,输出到UI的信息过频,导致UI假死。

    private void TestMakeTasks(object obj)
{
string msg = ""; //循环创建task
for (int i = 0; i < 3000; i++)
{
//主线程(winform)--子线程(Thread)--工作线程(task)
//不能在循环里面连续访问UI,会造成UI来不及处理,导致假死。
Task<string> tt = Task.Factory.StartNew<string>(test, i);
tt.ContinueWith((t) =>
{
if (t.IsFaulted)
{
string msgexcep = (string.Format("I have observed a {0}", t.Exception.InnerException.GetType().Name));
Interlocked.Increment(ref responsecount);
Interlocked.Decrement(ref threadscount);
}
});
//Thread.Sleep(1); //避免过快发送UI更新请求,导致假死。
msg = " 已发送请求数:" + requestcount.ToString() + " 已完成请求数:" + responsecount.ToString(); //输出线程建立信息给UI,过频会导致假死。
PublishStatus(msg); Interlocked.Increment(ref threadscount);
Interlocked.Increment(ref requestcount);
if (_isStop)
{
PublishMessage("正在退出...\r\n");
break;
}
}
PublishMessage("发送完毕,请等待线程运行完毕!\r\n");
while (responsecount < requestcount)
{
Thread.Sleep(300);
msg = "!已发送请求数:" + requestcount.ToString() + " 已完成请求数:" + responsecount.ToString();
PublishStatus(msg);
}
_isRunning = false;
PublishMessage("\r\n全部线程运行完毕!\r\n");
}

  为了解决这个问题,考虑使用publisher模式控制UI输出

public class Publisher
{
public bool isbusy = false; //标志
public delegate void PublishEventHander(object sender, PubEventArgs e); public event PublishEventHander PublishMessage;
public event PublishEventHander PublishStatus; //声明一个可重写的OnPublish的保护函数
protected virtual void OnPublishMessage(PubEventArgs e)
{
if (PublishMessage != null)
{
//Sender = this,也就是Publisher
this.PublishMessage(this, e);
}
}
protected virtual void OnPublishStatus(PubEventArgs e)
{
if (PublishStatus != null)
{
//Sender = this,也就是Publisher
this.PublishStatus(this, e);
}
} /// <summary>
/// 触发publish message事件
/// </summary>
public void IssueMessage(string message)
{
OnPublishMessage(new PubEventArgs(message));
} /// <summary>
/// 触发publish status事件
/// </summary>
public void IssueStatus(string message)
{
if (!isbusy) OnPublishStatus(new PubEventArgs(message)); }
}

  同时,在UI输出部分,使用Invoke来阻止更多的UI操作(不能使用BeginInvoke)。

    private void WriteStatus(string msg)
{
if (this.lblStatus.InvokeRequired)
{
Invoke(cdWriteStatus, msg);
}
else
{
UpdatelblMethod(msg);
}
}

  

大致思路是 task创立任务之后,发给publisher一个通知(使用IssueStatus函数),publisher通过OnPublishStatus事件通知给Subscriber,UI界面作为订阅者通过设置publisher的busy状态使得publisher取消后面多余的输出事件。

有问题请联系QQ 564955427

使用publisher模式控制频繁的UI输出,避免Winform界面假死的更多相关文章

  1. Qt多线程和GUI界面假死(run()是线程的入口,就像main()对于应用程序的作用。分析QThread::exec函数的源码,旧的QMutexLocker模式其实很好用,挡住别人进入抢占资源,可照抄)good

    QThread的常见特性: run()是线程的入口,就像main()对于应用程序的作用.QThread中对run()的默认实现调用了exec(),从而创建一个QEventLoop对象,由其处理该线程事 ...

  2. TIMER门控模式控制PWM输出长度

    TIMER门控模式控制PWM输出长度 参照一些网友代码做了些修改,由TIM4来控制TIM2的PWM输出长度, 采用主从的门控模式,即TIM4输出高时候TIM2使能输出 //TIM2 PWM输出,由TI ...

  3. STM32: TIMER门控模式控制PWM输出长度

    搞了两天单脉冲没搞定,无意中发现,这个利用主从模式的门控方式来控制一路PWM的输出长度很有效. //TIM2 PWM输出,由TIM4来控制其输出与停止 //frequency_tim2:TIM2 PW ...

  4. AMQ学习笔记 - 19. 问题解决 - 控制Atomikos的日志输出

    概述 在使用Atomikos为ActiveMQ提供JTA支持时,Atomikos在控制台打印了繁琐的日志.这里介绍如何控制Atomikos日志输出的粒度. 解决方案 基于以下三个事实: Atomiko ...

  5. Client-Side UI Automation Provider - WinForm Sample

    Client-Side UI Automation Provider -  WinForm Sample 2014-09-15 源代码 目录 引用程序集实现提供程序接口分发客户端提供程序注册和配置客户 ...

  6. Server-Side UI Automation Provider - WinForm Sample

    Server-Side UI Automation Provider - WinForm Sample 2014-09-14 源代码  目录 引用程序集提供程序接口公开服务器端 UI 自动化提供程序从 ...

  7. 告诉你吧,一套皮肤在winform与wpf开发模式下实现的界面效果同样精彩,winform界面和wpf界面。

    一.同一资源: 二.先上软件界面: (1)wpf界面: 在wpf中实现这样类似web风格的软件界面就不用我多说了,在wpf实现这样的风格是很简单的,完全像网页设计一样的. (2)winform界面 在 ...

  8. C#:控制WinForm界面的显示

    控制WinForm界面在屏幕的四个角落显示,具体代码中有说明: using System; using System.Collections.Generic; using System.Drawing ...

  9. Winform 界面执行耗时操作--UI卡顿假死问题

    UI卡顿假死问题 误区1:使用不同的线程操作UI控件和耗时操作(即,跨线程操作UI控件CheckForIllegalCrossThreadCalls = false;), 注意:此处只是为了记录... ...

随机推荐

  1. Python操作字典(dict)

    一.字典定义 >>> dict={} 二.字典元素添加 >>> dict['性别']='男' >>> dict {'性别': '男'} >& ...

  2. Windows Server 2016-Powershell管理站点复制

    对于Active Directory的Windows PowerShell包括管理复制.网站.域和森林,域控制器以及分区的能力.例如Active Directory的站点和服务管理单元和repadmi ...

  3. 关于java中assert(断言)的使用讲解

    说明:写的不是很全面,有任何问题请留言,多交流,谢谢! 1.eclipse.myeclipse开启assert(断言),默认是关闭,如下: 说白了就是设置一下jvm的参数,参数是-ea或者-enabl ...

  4. Python: datetime 转换

    Directive Meaning Example Notes %a Weekday as locale’s abbreviated name. Sun, Mon, …, Sat (en_US); S ...

  5. 【PAT】B1004 成绩排名

    简单题 循环输入放入结构体数组,一个sort搞定 #include <stdio.h> #include<algorithm> using namespace std; str ...

  6. 关于pycharm中使用charts无法显示图表的问题(属于个人粗心问题)

    在练习用charts库对爬取的数据进行数据分析并图表化时遇到一个问题,无法显示图表,如下: 经过重装charts库等一顿折腾后,终于发现一个问题,看这里: def data_gen(type): le ...

  7. MySQL高级知识(七)——索引面试题分析

    前言:该篇随笔通过一些案例,对索引相关的面试题进行分析. 0.准备 #1.创建test表(测试表). drop table if exists test; create table test( id ...

  8. linux学习笔记整理(七)

    第八章 Centos7软件包的管理与安装本节所讲内容:8.1 使用rpm命令-安装-查看-卸载-rpm软件包8.2 yum管理软件包8.3 实战tar源码包管理-srpm源码包安装方法 8.1 软件包 ...

  9. centos7下安装docker(19容器架构)

    What,Why,How What:什么是容器? 说起容器大家想到的是什么?      集装箱(container),虚拟机,docker,k8s 1. 没毛病,因为容器与集装箱的英文都可以翻译成co ...

  10. 解决y7000笔记本ubuntu下wifi无法连接问题

    查看wifi与蓝牙硬件开关,发现ideapad的硬件模块都是关闭的 rfkill list all 打开终端 输入 sudo gedit /etc/rc.local 写入以下内容 进行保存 #!/bi ...