通过例子编写,用winform编写的,讲解单线程与多线程使用,用于异步加载数据,界面不会卡死,数据在后台默认加载,给用户更好的体验。稍后会附加完整代码。

1、先不用线程,显示一个求和,计算过程中要停留1秒后继续计算。如果不用多线程页面就会卡死,直到计算完成后才会响应。一个button按钮,一个label

界面:

代码如下:

  #region 不用线程情况
private void button1_Click(object sender, EventArgs e)
{
//不用线程点击按钮,窗体会卡死,10秒后恢复
int sum = ;
for (int i = ; i < ; i++)
{
sum = sum + i;
label3.Text = sum.ToString();
Thread.Sleep();//休息1秒
}
}
#endregion

2、用单线程进行处理,单独开启一个进线程启动,进行每个2秒钟进行计数显示,并且窗体不会死。界面是一个button 两个 label。

界面:

代码:

    #region 多线程中,单独一个线程运行
private void btnD_Click(object sender, EventArgs e)
{
//多线程中,单独一个进程启动,进行每个2秒钟进行计数显示,并且窗体不会死。
Thread t = new Thread(new ThreadStart(OneThreadSum));//开启线程
t.IsBackground = true;//附加主线程,主线程关闭后,子线程也跟着关闭,简单理解就是窗体关闭,启动线程也跟着关闭。
t.Start();
}
private void OneThreadSum()
{
try
{
Invoke(this, delegate
{
//按钮变为灰色 防止按钮多次点击
//给控件赋值就需要使用invoke
this.btnD.Enabled = false;
}); for (int i = ; i < ; i++)
{
Invoke(this, delegate
{
//通过代理赋值,通过这种方式,界面和窗口就不会卡死,窗口先展示出来,然后数据过后加载。
//给控件赋值就需要使用invoke
label2.Text = i.ToString();
});
Thread.Sleep();//休息2秒
}
}
catch (Exception ex)
{ throw;
}
finally
{
//给控件赋值就需要使用invoke
Invoke(this, delegate
{
this.btnD.Enabled = true;
});
} }
/// <summary>
/// 在线程中通过代理给控件赋值
/// </summary>
/// <param name="col"></param>
/// <param name="method"></param>
public void Invoke(Control col, MethodInvoker method)
{
if (!col.IsHandleCreated) return;//当前控件是否被创建
if (col.IsDisposed) return;//当前控件是否被销毁
if (col.InvokeRequired) col.Invoke(method);//是否允许被请求
else method();
}
#endregion

3、模拟餐馆来人吃饭,客人来了点菜是一个线程,客人就餐时一个线程,客人结账时一个线程,一共3个线程,各自处理各自的事情,一个客人名称textbox, 一个客人来了button,一个启动初始化按钮,listbox1 代表点餐记录 ,listbox2 代表就餐记录 ,listbox3代表结账记录 。

界面:

代码:

     #region 用多线程 不是单独一个线程,以3个线程为例
//模拟餐馆来人吃饭,客人来了点菜是一个线程,客人吃饭时一个线程,客人结账时一个线程,一共3个线程 private void 启动监听线程_Click(object sender, EventArgs e)
{
启动监听线程.Enabled = false;//初始化只允许一次,否则会开启很多线程,所以要灰色
wait1 = new ManualResetEvent(false);//启动信号,等待着。
t1 = new Thread(new ThreadStart(F1)) { IsBackground = true };
t1.Start();//初始化线程t1 点餐线程 wait2 = new ManualResetEvent(false);
t2 = new Thread(new ThreadStart(F2)) { IsBackground = true };
t2.Start();//初始化线程t2 用餐线程 wait3 = new ManualResetEvent(false);
t3 = new Thread(new ThreadStart(F3)) { IsBackground = true };
t3.Start();//初始化线程t3 结账线程
}
private void 客人来了_Click(object sender, EventArgs e)
{
data1.Add(textBox1.Text);//这个时候客人来了,增加到list中。
wait1.Set();//告诉服务员,客人来了,要开始点餐了。
}
private IList data1 = new ArrayList();//存储来客人
private Thread t1 = null;//点菜线程
private ManualResetEvent wait1 = null;//信号,相当于服务员,客人来了需要告诉
private void F1()
{
while (true)
{
//2秒钟查询一次。
if (wait1.WaitOne(, false))
{
if (data1 == null || data1.Count == )
{
//如果一个人都没有的话,不需要点菜
Invoke(this, delegate
{
listBox1.Items.Add("无客人!");
});
wait1.Reset();//线程停止,继续等待。
continue;//结束本次循环
}
//程序执行到这里说明有人,客人开始点餐。
string r = data1[] as string;
Invoke(this, delegate
{
listBox1.Items.Add(r + "->开始点餐!");
});
Thread.Sleep(); data2.Add(r);//增加到用餐list中
wait2.Set();//告诉可以开始用餐了。 data1.RemoveAt();//客人从队列中移除
}
}
} private IList data2 = new ArrayList();//存储用餐人
private Thread t2 = null;//用餐线程
private ManualResetEvent wait2 = null;//信号,用餐信号
private void F2()
{
while (true)
{
if (wait2.WaitOne(, false))
{
if (data2 == null || data2.Count == )
{
Invoke(this, delegate
{
listBox2.Items.Add("无用餐人!");
});
wait2.Reset();
continue;
}
//程序执行到这里说明有人,客人开始用餐。
string r = data2[] as string; Invoke(this, delegate
{
listBox2.Items.Add(r + "->用餐中...!");
});
Thread.Sleep(); data3.Add(r);//增加到结账的list中
wait3.Set();//告诉客人可以开始结账了 data2.RemoveAt();//客人从队列中移除
}
}
} private IList data3 = new ArrayList();//存储结账人
private Thread t3 = null;//结账线程
private ManualResetEvent wait3 = null;//结账信号
private void F3()
{
while (true)
{
if (wait3.WaitOne(, false))
{
if (data3 == null || data3.Count == )
{
Invoke(this, delegate
{
listBox3.Items.Add("无结账人!");
});
wait3.Reset();
continue;
}
//程序执行到这里说明有人,客人开始结账。
string r = data3[] as string; Invoke(this, delegate
{
listBox3.Items.Add(r + "->结账买单!");
});
Thread.Sleep(); data3.RemoveAt();//客人从队列中移除
}
}
} /// <summary>
/// 在线程中通过代理给控件赋值
/// </summary>
/// <param name="col"></param>
/// <param name="method"></param>
public void Invoke(Control col, MethodInvoker method)
{
if (!col.IsHandleCreated) return;//当前控件是否被创建
if (col.IsDisposed) return;//当前控件是否被销毁
if (col.InvokeRequired) col.Invoke(method);//是否允许被请求
else method();
} #endregion

csdn 源码下载链接:https://download.csdn.net/download/njxiaogui/12514492

C#winform单线程事例与多线程事例的更多相关文章

  1. WinForm中 事件 委托 多线程的应用

    WinForm中 事件 委托 多线程的应用[以一个下载进度条为例] 第一步:首先我们创建一个winfor的项目 第二步:我们建一个窗体在一个窗体里面 打开一个另外的窗体 另外的窗体有一个按钮 点击后就 ...

  2. GDB:从单线程调试到多线程调试(MFiX单步调试)

    GDB:从单线程调试到多线程调试 1. 裸跑GDB 1.1 安装GDB sudo apt-get install gdb 1.2 编译程序 由于需要调试,因此编译的时候需要添加-g编译参数: 1.3 ...

  3. ROS的单线程Spinning和多线程Spinning

    单线程Spinning ros::spin()是最简单的单线程自旋, 它会一直调用直到结束 用法:  ros::spin(); 另一个单线程spinning是ros::spinOnce(),它定期调用 ...

  4. 关于Winform 2.0以后多线程不能更新UI的办法

    DotNet 2.0以后Winform在多线程Debug模式下更新UI会报这个错: 线程间操作无效: 从不是创建控件"XXX"的线程访问它. 解决办法如下: 1.在Winform的 ...

  5. JAVA单线程以及java多线程的实现方式

    1.java单线程的实现 public class SingletonThread { @SuppressWarnings("static-access") public stat ...

  6. 【winform】主窗体多线程给子窗体传值

    1.主窗体多线程给子窗体传值 解决方案:主要使用委托,因为会出现跨线程错误 主窗体 public FormMain() { InitializeComponent(); //background th ...

  7. WinForm中 事件 委托 多线程的应用【以一个下载进度条为例】

    第一步:首先我们创建一个winfor的项目 第二步:我们建一个窗体 在一个窗体里面 打开一个另外的窗体 另外的窗体有一个按钮 点击后就开始下载 下载完成后 在注册窗体上面 显示下载完成(达到在一个窗体 ...

  8. 在单进程单线程或单进程多线程下实现log4cplus写日志并按大小切割

    基于脚本配置来过滤log信息 除了通过程序实现对log环境的配置之外.log4cplus通过PropertyConfigurator类实现了基于脚本配置的功能.通过 脚本能够完毕对logger.app ...

  9. 单线程爬虫VS多线程爬虫的效率对比

    单线程爬虫: import re import requests import time url_EB = 'http://www.amazon.com/gp/search/other/ref=sr_ ...

随机推荐

  1. 初涉WebGL

    之前一直在捣鼓Vue和React栈,对组件化架构项目有了些理解和体会.今天尝尝WebGL,当然,并不打算现在深入,只是略作了解,我知道这个坑很深. js的图形库.3d库也有好几款比较流行的,如游戏开发 ...

  2. 2-SAT问题简述

    前置知识 强连通分量 k-SAT问题 k-SAT问题中的SAT意思就是(stability),也就是适应性问题.本意是给出n个变量,每一个变量有k个状态,并且也给出一些约束条件,要求你求出是否存在每一 ...

  3. MySQL表的CRUD及多表查询

    数据库表的增删改查操作: 增.删.改 查: 单表查询 简单查询.where约束.group by分组.聚合查询.having过滤.order by排序.limit限制.正则匹配 多表查询 连表查询:交 ...

  4. 201771010128王玉兰《面向对象程序设计(Java)第十四周学习总结》

    第一部分:理论知识总结: (1)Swing 设计模式(Design pattern)是设计者一种流行的 思考设计问题的方法,是一套被反复使用,多数人 知晓的,经过分类编目的,代码设计经验的总结. 使用 ...

  5. 处理TableVIew SectionHeader悬停问题

    1,plain类型的tableview  才会悬停  grouped类型不会悬停 2,通过改变contentInset达到部分悬停遮罩的处理,对所有的Sectionheader都有效,不可以单独处理某 ...

  6. E. Alternating Tree 树点分治|树形DP

    题意:给你一颗树,然后这颗树有n*n条路径,a->b和b->a算是一条,然后路径的权值是 vi*(-1)^(i+1)  注意是点有权值. 从上头往下考虑是点分治,从下向上考虑就是树形DP, ...

  7. 1417. 重新格式化字符串--来源:力扣(LeetCode)

    题目描述: 给你一个混合了数字和字母的字符串 s,其中的字母均为小写英文字母. 请你将该字符串重新格式化,使得任意两个相邻字符的类型都不同.也就是说,字母后面应该跟着数字,而数字后面应该跟着字母. 请 ...

  8. CICD:Jenkins入门和使用

    最近,我们使用的开发服务器被回收了,换了一台新的服务器,CI/CD平台需要重新搭建. 我的运维能力一直薄弱,所以借此机会学习了一番如何使用Jenkins进行持续集成开发和部署,实践并踩了一些坑,在此记 ...

  9. Vue接入百度地图显示及相关操作

    Vue接入百度地图的API 首先你要有一个百度地图的key就是CK 申请网址:http://lbsyun.baidu.com/index.php?title=jspopular/guide/getke ...

  10. Ubuntu虚拟机的安装

    1.在VMware中新建虚拟机 注意W10的现在强制升级VMware所以大家,安装低版本的时候提示,升级就区官网下载一个新版本的即可. 这边大家填写自己的就好,要记住自己填写的! 这边我们等一会即可. ...