DotNET多线程使用初探

最近几周一直在做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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux mount: Structure needs cleaning 错误解决方法

“mount: Structure needs cleaning”报错可以使用xfs_repair来修复&#xff0c;但是要注意 xfs_repair修复的分区中的文件都会丢失&#xff0c;即使是du能正常显示的文件也会丢失。 [rootyw-0-0 /]# mount -a mount: Structure needs cleaning[rootyw-0-0 /]# xfs_repair /dev…

大数据——Spark学习笔记(配置)

Spark运行环境 spark ui web http://hadoop102:8080 历史服务器 http://hadoop102:18080 一. 本地模式(Local)——单机运行 本地模式&#xff1a;运行 bin/spark-shell提交应用&#xff1a;运行 bin/spark-submit --class org.apache.spark.examples.SparkPi …

Linux软件安装——安装软件的命令

Linux软件安装——安装软件的命令 摘要&#xff1a;本文主要学习了如何在Linux系统中安装、更新、卸载软件。 rpm命令 rpm命令用来在Linux系统上进行软件的安装。 基本语法 安装命令&#xff1a; 1 rpm -ivh 包全名 如果没有安装则安装&#xff0c;如果已经安装则升级&#xff…

JavascriptHelp

阅读全文&#xff1a;http://www.cckan.net/forum.php?modviewthread&tid147usingSystem;usingSystem.Data;usingSystem.Configuration;usingSystem.Web;usingSystem.Web.Security;usingSystem.Web.UI;usingSystem.Web.UI.WebControls;usingSystem.Web.UI.WebControls.Web…

GoLang之方法与接口

GoLang之方法与接口 Go语言没有沿袭传统面向对象编程中的诸多概念&#xff0c;比如继承、虚函数、构造函数和析构函数、隐藏的this指针等。 方法 Go 语言中同时有函数和方法。方法就是一个包含了接受者&#xff08;receiver&#xff09;的函数&#xff0c;receiver可以是内置类…

孙继海化装

于输得太惨&#xff0c;中国球员怕回国被球迷打&#xff0c;孙继海决定化装成“乞丐”。化好之后遇到一个老太太&#xff0c;他想看看自己化装的效果&#xff0c;就给了老太太100块钱&#xff0c;问&#xff1a;“你知道我是谁吗&#xff1f;”老太太看了看说&#xff1a;“你是…

sql 时间函数

1. 当前系统日期、时间 select getdate() 2. dateadd 在向指定日期加上一段时间的基础上&#xff0c;返回新的 datetime 值 例如&#xff1a;向日期加上2天 select dateadd(day,2,’2004-10-15′) –返回&#xff1a;2004-10-17 00:00:00.000 3. datediff 返回跨两个指定日期的…

大数据——Hive学习笔记

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData

Eclipse 常用快捷键

Eclipse 常用快捷键 快捷键 描述 编辑 Ctrl1 快速修复&#xff08;最经典的快捷键,就不用多说了&#xff0c;可以解决很多问题&#xff0c;比如import类、try catch包围等&#xff09; CtrlShiftF 格式化当前代码 CtrlShiftM 添加类的import导入 CtrlShiftO 组织类的…

[Story]狗尾草花园

不知道为什么&#xff0c;很多年过去&#xff0c;我却依然记得这个故事。很小的时候&#xff0c;大概四、五岁吧&#xff0c;在河滩上和几个姐姐&#xff0c;一起玩过家家。他们大概十三&#xff0c;四岁吧&#xff0c;反正比我大好多。分成两组&#xff0c;我在我们一组当然是…

UML各种图

转载自&#xff1a; https://www.cnblogs.com/jiangds/p/6596595.html UML&#xff08;Unified Modeling Language&#xff09;是一种统一建模语言&#xff0c;为面向对象开发系统的产品进行说明、可视化、和编制文档的一种标准语言。下面将对UML的九种图包图的基本概念进行介绍…

Interactive Reflection Editing (SIGGRAPH ASIA 09)

讓使用者可以將reflection做editing 以達到使用者想要的結果INPUT: a 3d scene大部分是針對卡通等NPR的場景 對於reflection做editing利用shader也可以控制reflection這篇可以讓使用者做更動沒有使用BRDF做reflection的計算转载于:https://www.cnblogs.com/GameJan/archive/201…

大数据——Hive学习笔记(配置)

具体代码可以参考&#xff1a; https://github.com/Ostrich5yw/java4BigData

CSDN-markdown编辑器语法——字体、字号与颜色

Markdown是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过类似HTML的标记语法&#xff0c;它可以使普通文本内容具有一定的格式。但是它本身是不支持修改字体、字号与颜色等功能的&#xff01; CSDN-markdown编辑器是其衍生版本&#xff0c;扩展了Markdown的功能&a…

思科携手中兴掌握3G话语权 剑指华为3COM组合

思科携手中兴掌握3G话语权 剑指华为3COM组合 中国电信市场又迎来了一次中外巨头的牵手。昨日,思科系统公司和中兴通讯股份有限公司共同宣布,双方已签署了一份战略合作协议,将进行范围广泛的合作。这也是林正刚上任思科系统中国总裁后,祭出的首个“中国攻略”。 根据协议,两家公…

JS服务器端开发基础篇(Array.slice方法和splice方法)

Array.slice方法和splice方法在众多的JS数组中属于比较复杂的一个方法&#xff0c;而且容易记混。搜索网络上很多资料都没有发现系统的总结。特别归纳如下&#xff0c;不完全处还希望各位批评指正。一、slice方法格式&#xff1a;arrayObj.slice(start, [end])功能&#xff1a;…

HashMap(摘)

1.HashMap简介 HashMap基于哈希表的Map接口实现&#xff0c;是以key-value存储形式存在。&#xff08;除了不同步和允许使用 null 之外&#xff0c;HashMap 类与 Hashtable 大致相同。)HashMap 的实现不是同步的&#xff0c;这意味着它不是线程安全的。它的key、value都可以为n…

LeetCode—274. H 指数

274. H 指数 题目描述&#xff1a; 给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。 根据维基百科上 h 指数的定义&#xff1a;h 代表“高引用次数”&#xff0c;一名科研人员的 h指数是指他…

【创业】创业团队的那些事(二)

在上一篇&#xff08;创业团队的那些事&#xff08;一&#xff09;&#xff09;从邮件中看到很多博友的评论&#xff0c;很行赏他们的观点&#xff0c;关于创业团队&#xff0c;我们都有说不完的理论&#xff0c;想不完的创意&#xff0c;干不完的事情&#xff0c;永远无法预知…

日常经典用语、成语及谚语

cross your heart 你发誓       gate - crasher 不请自来的不速之客      take it easy 凡事看开些, 不要太冲动, 不要看得那么重       make yourself comfortable 不用约束 (招待客人时说的话)       you are all wet 你完全误会了       she …