最近几周一直在做DotNET WinForm开发,陆陆续续有些收获,希望能够有空好好整理整理。记下来以免以后又忘了。:-)


一、最简单的线程使用方法

新建一个C# Windows应用程序项目,在最前面的引用代码那增加一行
using System.Threading;
在界面上扔个Button和Label,再写几行简单的代码,就是一个最简单的线程例子啦
private void button1_Click(object sender, System.EventArgs e)
{
 Thread t = new Thread(new ThreadStart(myRun));
 t.Start();
}

private void myRun()
{
 for(int i=0; i<1000000; i++)
 {
  if (i % 1000 == 0)
   label1.Text = i.ToString();
 }
}

当然,这个例子没有处理线程之间同步之类关系。你试试快速点几下Button就知道有什么好玩的事情发生了。

二、给线程传递参数

ThreadStart 委托没有参数也没有返回值。其声明为 public delegate void ThreadStart();
所以不能直接给线程传递参数。但是我们可以把线程函数封装到一个类里,给类的实例传递参数(可以在创建实例时,也可以用另外的函数来传递。这不是重点)。因为DotNET自由线程的特点,在线程中是可以访问同一个类里的数据的。
我们更改上面的简单例子,尝试给线程传递一个循环的终止值。
首先是弄个类把 myRun 函数装进去 :-) 注意要公开函数(public)
 public class myThreadClass
 {
  private int Max = 0;
  public myThreadClass(int initValue)
  {
   Max = initValue;
  }

public void myRun()
  {
   for(int i=0; i   {
    if (i % 1000 == 0)
     label1.Text = i.ToString();
   }
  }
 }
然后,Button事件有点小改动,如下:
myThreadClass myThread = new myThreadClass(800000);
Thread t = new Thread(new ThreadStart(myThread.myRun));
t.Start();
仅仅是多了一行,很简单是吧?

编译,出错啦!找不到类型或命名空间名称"label1"
注意到我们原来是直接在Form实例中使用label1,现在将myRun装到另外的类里,当然不能直接访问label1啦。怎么办?
一样,弄成个参数,传给myThreadClass就行。修改后的程序如下:
 public class myThreadClass
 {
  private int Max = 0;
  object obj = null;

public myThreadClass(int initValue, object initObj)
  {
   Max = initValue;
   obj = initObj;
  }

public void myRun()
  {
   for(int i=0; i   {
    if (i % 1000 == 0)
     if (obj != null)
       (obj as Label).Text = i.ToString();
   }
  }
 }
下面是Form1中的按钮事件
  private void button1_Click(object sender, System.EventArgs e)
  {
   myThreadClass myThread = new myThreadClass(800000, label1);
   Thread t = new Thread(new ThreadStart(myThread.myRun));
   t.Start();
  }
好了,运行下看看,是不是和原来的效果一模一样。差别在于调用线程的时候,你可以传递参数,把握线程的运行时间。

三、获得线程的返回值

第二部分解决了线程参数的问题,这部分我们来解决返回值的问题。
我们注意到,第二部分的代码,会把线程的中间运行状态的值写到Form1的label1.Text中,那么,我们能不能从这里动手脚呢?试试看。
往Form1上扔个进度条ProgressBar先,myThreadClass我们暂时先不动,只改Button事件:
  private void button1_Click(object sender, System.EventArgs e)
  {
   const int Max = 800001;
   progressBar1.Maximum = Max;
   progressBar1.Value = 0;
   myThreadClass myThread = new myThreadClass(Max, label1);
   Thread t = new Thread(new ThreadStart(myThread.myRun));
   t.Start();
   while ( t.IsAlive )
   {
    progressBar1.Value = Int32.Parse(label1.Text.ToString());
    progressBar1.Refresh();
    Thread.Sleep(0);
   }
  }
运行一下,结果是不行!窗体完全失控了。如图:


分析下原因。很显然,是那个while搞的鬼!让窗体主线程在这里不停的循环、执行。根本没有多余的力气来更新窗体界面显示啦!

此路不通!那怎么办好呢?答案就是 回调函数。
首先,声明一个回调函数原型,在我们这个例子中,只需要取得一个返回值,所以回调函数的参数只有一个,如果有更多返回值,可相应修改。
namespace TestThread
{
 public delegate void ThreadCallback(int i);

public class Form1 : System.Windows.Forms.Form

然后修改myThreadClass类,不再需要传递label1给线程了。因为我们将在回调函数中获得线程当前循环的值,然后由回调函数自个来更新label1.Text,同时还要更新progressBar1。
但要传递给线程的参数扔是两个,一个是initValue用来控制循环的,一个是ThreadCallback callbackDelegate,即回调函数。修改后的myThreadClass类代码如下:
 public class myThreadClass
 {
  private int Max = 0;
  private ThreadCallback callback;

public myThreadClass(int initValue, ThreadCallback callbackDelegate)
  {
   Max = initValue;
   callback = callbackDelegate;
  }

public void myRun()
  {
   for(int i=0; i   {
    if (i % 1000 == 0)
     if (callback != null)
       callback(i);
   }
  }
 }

回到Form1,先写个回调函数ThreadCallback 的具体实现
  public void myCallback(int i)
  {
   label1.Text = i.ToString();
   label1.Refresh();
   progressBar1.Value = i;
   progressBar1.Refresh();
  }
接着修改Button事件
  private void button1_Click(object sender, System.EventArgs e)
  {
   const int Max = 800001;
   progressBar1.Maximum = Max;
   progressBar1.Value = 0;
   myThreadClass myThread = new myThreadClass(Max, new ThreadCallback(myCallback));
   Thread t = new Thread(new ThreadStart(myThread.myRun));
   t.Start();
  }
代码中,通过new ThreadCallback(myCallback),给线程传了回调函数。

OK!
改动都不算多。我们运行下看看吧!一切顺利!如图:

label1和progressBar1同步更新状态。而且在线程运行时,拖动主窗体也不会失去控制了,没有任何问题。

后文

本文是《DotNET多线程使用初探》,故不是详细的DotNET多线程使用说明。多线程还有很多其它方面,如生存期、线程间同步、死锁问题、STA、MTA、线程池等等等等。
本文起源于我在DotNET开发中,处理一些复杂的数据库操作非常耗时,主窗体经常失去反应。这时就需要一些简单的线程操作。很必要的一个是给用户一个进度条。
如果你遇到的情况跟我相似,相信本文对你会有所帮助。

转载于:https://www.cnblogs.com/CrazyWill/archive/2005/08/25/222579.html

DotNET多线程使用初探相关推荐

  1. MySQL\MariaDB 多线程复制初探

    背景: MariaDB 在10.0.5就已经支持了并行复制的功能,即从库多线程复制的功能.MySQL最先在5.6.3中支持.目前暂时没有用MySQL5.6的版本,故暂时只对MariaDB进行一些说明, ...

  2. DotNet 多线程下载

    public class MultiDownload{#region 初始化参数private int bufferSize = 512;//缓冲池大小private int threadNum;// ...

  3. C#的多线程机制初探 (引自 http://www.daima.com.cn/info/234.htm ,在此感谢原作者)

    注:本文中出现的代码均在.net Framework RC3环境中运行通过 一.多线程的概念 Windows是一个多任务的系统,如果你使用的是windows 2000及其以上版本,你可以通过任务管 ...

  4. 多线程编程初探——OO第二单元作业回顾

    一.作业设计策略 1)执行FAFS策略的单部电梯 ​ 由于对多线程不是很了解,于是采用了理论课上介绍的生产者消费者模型作为设计模板(也是很多同学一开始的做法):将请求队列作为共享对象(托盘),名为In ...

  5. python单核运行_python下多核,单核CPU对于并行,并发执行效率的对比-Go语言中文社区...

    ** ** 这篇博客主要内容为python 中多线程以及多进程的效率对比,以及记录自己在做这个实验中遇到的一些问题以及心得 背景引入: CPU制造商为了追求CPU效率放弃了在CPU频率上的追求(CPU ...

  6. Pyton学习(5)--socket编程,一个简单的对话框

    这次学习涉及以下几个问题: 1,同时运行两个python程序的方法 2,socket编程初探 3,多线程编程初探 4,GUI编程tix部分控件的属性 5,Python的list类型 1.同时运行两个程 ...

  7. C#多线程之旅(4)——APM初探

    阅读目录 一.简单的串行执行程序 二.使用委托来实现APM 源码地址:https://github.com/Jackson0714/Threads C#多线程之旅(4)--APM初探 v博客前言 先交 ...

  8. 新浪微博PC客户端(DotNet WinForm版)—— 初探

    最近兴趣使然尝试了一下使用DotNet技术实现新浪微博PC客户端,几天时间,目前实现登录.微博列表.发布纯文本微博功能,新浪API调用基本没什么难度,在微博列表形式处理上着实让我烦躁了一阵子,Wind ...

  9. 新浪微博PC客户端(DotNet WinForm C# 版,C#调用新浪微博API代码,源码下载)—— 初探 (第二部分内置链接)

    第二篇:新浪微博PC客户端(DotNet WinForm版)--功能实现分解介绍 C#源码下载 最近兴趣使然尝试了一下使用DotNet技术实现新浪微博PC客户端,几天时间,目前实现登录.微博列表.发布 ...

最新文章

  1. Svchost.exe病毒
  2. 解决iOS微信H5支付跳转微信后不返回App问题(Swift-WKWebview)(转)
  3. 文巾解题 面试题 17.10. 主要元素
  4. object-c中的bool
  5. Android 点击跳转到蓝牙设置界面
  6. Java面向对象入门
  7. 用户体验改善案例_用户体验案例研究:建立更好的体验(重新设计“和平航空”网站)...
  8. 数据结构之查找算法:分块查找
  9. 现在有一个map集合如下: Map<Integer,String> map = new HashMap<Integer, String>(); map.put(1, “
  10. 文本分类项目GPU版本代码
  11. Ubuntu 19.10 Beta 发布,正式版本定于 10 月份
  12. matlab 人脸识别_MATLAB基于PCALDA模糊神经网络的人脸识别
  13. Android4.2中Phone的P-sensor的应用的分析。
  14. PHP问题Parse error: syntax error, unexpected end of file in
  15. 微型计算机是嵌入式吗,什么是嵌入式计算机
  16. Python CSV模块
  17. 相对路径与绝对路径区别
  18. Druid (大数据实时统计分析数据存储)
  19. [转]部分日文实用网址介绍
  20. 总结——STM32F103C8T6通过MAX31865读取PT100电阻值

热门文章

  1. codeforce 227D Naughty Stone Piles (贪心+递归+递推)
  2. 数据结构-栈应用之逆波兰表达式(后缀表达式)
  3. MySql允许被远程访问
  4. uCOS-II核心算法分析(μCOS-Ⅱ)
  5. USB接口芯片的选型参考(Z)
  6. 节能以太网EEE(Energy Efficient Ethernet)
  7. DSP Builder
  8. 没有工作怎么申请贷款?
  9. 一个弱智问题, Ubuntu 中gedit 菜单栏在哪里?
  10. sourcetree mac 免登录_「vscode remote ssh 免登录」mac