惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
人人都是产品经理
人人都是产品经理
IT之家
IT之家
Cyberwarzone
Cyberwarzone
T
Troy Hunt's Blog
有赞技术团队
有赞技术团队
阮一峰的网络日志
阮一峰的网络日志
T
Threat Research - Cisco Blogs
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
G
GRAHAM CLULEY
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 叶小钗
Last Week in AI
Last Week in AI
C
CERT Recently Published Vulnerability Notes
The Hacker News
The Hacker News
Jina AI
Jina AI
T
Tor Project blog
V
Vulnerabilities – Threatpost
酷 壳 – CoolShell
酷 壳 – CoolShell
Spread Privacy
Spread Privacy
博客园_首页
C
Cybersecurity and Infrastructure Security Agency CISA
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Simon Willison's Weblog
Simon Willison's Weblog
Security Latest
Security Latest
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
博客园 - 司徒正美
V2EX - 技术
V2EX - 技术
I
Intezer
The Cloudflare Blog
Cisco Talos Blog
Cisco Talos Blog
SecWiki News
SecWiki News
博客园 - 【当耐特】
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
L
Lohrmann on Cybersecurity
Scott Helme
Scott Helme
Google Online Security Blog
Google Online Security Blog
量子位
The Last Watchdog
The Last Watchdog
AI
AI
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security Affairs
P
Palo Alto Networks Blog
S
Secure Thoughts
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Attack and Defense Labs
Attack and Defense Labs

博客园 - Danny Chen

python asyncio 获取协程返回值和使用callback c#等待所有子线程执行完毕方法 Python virtualenv 查看当前正在运行的python进程 Mac 删除/卸载 自己安装的python python读取txt文件最后一行(文件大+文件小) pycharm 注册码/License server 2017年最新 Linux cat命令详解 在Mac平台上安装配置ELK时的一些总结 Mac上搭建ELK C#中用schema验证xml的合法性 C#中XML与对象之间的序列化、反序列化 C#位运算 SQL Server 权限管理 如何用C#动态编译、执行代码 [C#]手把手教你打造Socket的TCP通讯连接(一) C#动态调用WCF接口,两种方式任你选。 动态调用WCF服务 矩阵的坐标变换(转)
【.NET线程--进阶(一)】--线程方法详解
Danny Chen · 2017-03-21 · via 博客园 - Danny Chen

上篇博客从线程的基本概况开始着重讨论了线程,进程,程序之间的区别,然后讨论了线程操作的几个类,并通过实例来说明了线程的创建方法。本篇博客将会带大家更深入的了解线程,介绍线程的基本方法,并通过一个Demo使用委托来调用线程之外的对象。

      前篇博客基础:【GDI+编程--番外篇(二)】--从事件看委托
                               【.NET线程--开篇】--线程从零开始

线程

   多线程优缺点

         多线程的使用会帮助程序提高响应速度,因为可以同时执行多个任务这样对比一个个的来完成任务来说提高了响应的速度,较之添加多CPU来说多线程提高了强大的技术来执行多个任务。虽然多线程提高了响应速度,但同时牺牲了资源,由于多线程的执行它会占用多个资源,为了避免资源访问的冲突,往往会在每个线程中都会创建自己的资源,这样导致了资源的浪费。另外如果线程过多,则其中大多数线程都不会产生明显的进度,如果大多数当前线程处于一个进程中,则其他进程中的线程的调度频率就会很低。

  线程基本方法

         下表包括了在线程编程过程中常用的基本方法。

可用于控制单个线程的方法

方法操作
Start  使线程开始运行。
Sleep 使线程暂停指定的一段时间。
Suspend 在线程到达安全点时,使其暂停。
Abort  在线程到达安全点时,使其停止。
Resume 重新启动挂起的线程
Join 使当前线程一直等到另一线程完成。 在与超时值一起使用时,如果该线程在分配的时间内完成,此方法将返回 True。

       Note: 安全点是指代码中公共语言运行时可以安全地执行自动“垃圾回收”的位置。垃圾回收是指释放不再使用的变量并回收内存的过程。 调用线程的 Abort 或 Suspend 方法时,公共语言运行时将对代码进行分析,确定让线程停止运行的适当位置。

  Demo1:线程,方法--委托

       自己做的一个小Demo来实现多线程,当点击开始按钮后会在文本框中填写数字,与此同时加载进度条,读取进度,点击暂停后线程会停止。另外可以在文本框中输入暂停时间来指定线程暂停时间,在暂停后继续执行。

       Demo下载地址:线程常用方法示例

       在点击开始按钮后会同时创建两个线程,分别为showNumThread和pBarThread,用来向文本框中写入数字和加载进度条。这里需要说明的是,一般情况下线程内部是不允许调用线程外创建的对象的,创建的两个线程都调用了线程外部的对象,是怎么实现的呢?使用的是委托来异步执行程序来实现了调用线程外部的方法。

  1. private void btnStart_Click(object sender, EventArgs e)  
  2. {  
  3.     pBarThread = new Thread(new ThreadStart(this.ExepBarShow)); 
  4.     showNumThread = new Thread(new ThreadStart(this.ExeShowNum));   
  5.     
  6.     this.StartThread(showNumThread);      
  7.     this.StartThread(pBarThread);  
  8. }  
  9.   
  10. private void ExeShowNum()  
  11. {  
  12.     try  
  13.     {  
  14.         MethodInvoker mInvoker = new MethodInvoker(this.ShowNumToText); 
  15.   
  16.         
  17.         while (true)  
  18.         {  
  19.             this.BeginInvoke((Delegate)mInvoker);   
  20.             Thread.Sleep(1000);     
  21.         }  
  22.     }  
  23.     catch { }  
  24. }  
  25.   
  26. private void ShowNumToText()  
  27. {  
  28.     i = i + 1;  
  29.     txtNum.Text = txtNum.Text + " " + (i + 1).ToString();   
  30. }  
  31.   
  32. private void ExepBarShow()  
  33. {  
  34.     try  
  35.     {  
  36.         MethodInvoker mInvoker = new MethodInvoker(this.pBarShow);  
  37.   
  38.         
  39.         while (true)  
  40.         {  
  41.             this.BeginInvoke((Delegate)mInvoker);  
  42.             Thread.Sleep(10);  
  43.         }  
  44.     }  
  45.     catch { }  
  46. }  
  47.   
  48. private void pBarShow()  
  49. {  
  50.     this.pgBar.PerformStep();  
  51. }  
  52.   
  53. private void StartThread(Thread th) {  
  54.     th.Start();  
  55. }  
  56.   
  57. private void EndThread(Thread th) {  
  58.     th.Interrupt(); 
  59.     th.Abort(); 
  60.     th = null;  
  61. }  
  62.   
  63. private void btnStop_Click(object sender, EventArgs e)  
  64. {  
  65.     try  
  66.     {  
  67.         this.TestThead();   
  68.         this.EndThread(this.pBarThread);    
  69.         this.EndThread(this.showNumThread); 
  70.     }  
  71.     catch (Exception ex)  
  72.     {  
  73.         
  74.         MessageBox.Show(ex.Message , "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  75.     }  
  76.               
  77. }  
  78.   
  79. private void btnEnd_Click(object sender, EventArgs e)  
  80. {  
  81.     try  
  82.     {  
  83.         this.TestThead();   
  84.         this.EndThread(this.pBarThread);
  85.         this.EndThread(this.showNumThread); 
  86.         txtNum.Text = "";   
  87.         i = 0;  
  88.         this.pgBar.Value = 0;
  89.     }  
  90.     catch (Exception ex)  
  91.     {  
  92.         
  93.         MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  94.     }       
  95. }  
  96.   
  97. private void btnStopMinute_Click(object sender, EventArgs e)  
  98. {  
  99.     try  
  100.     {  
  101.         int j = int.Parse(textBox1.Text);   
  102.         Thread.Sleep(j);    
  103.     }  
  104.     catch (Exception ex)  
  105.     {  
  106.         MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);  
  107.     }          
  108. }  
  109.   
  110. private void TestThead() {  
  111.     if (pBarThread ==null)  
  112.     {  
  113.         throw new Exception ("未创建线程,请创建线程后操作!");  
  114.     }  
  115.   
  116.     if (showNumThread  == null)  
  117.     {  
  118.         throw new Exception ("未创建线程,请创建线程后操作!");  
  119.     }  
  120. }  

  Demo2:Join方法使用实例

       Join方法能在指定的线程中插入一个线程,当插入的线程执行完成后才会继续执行被插入的线程。.NET为我们重载了此方法,能够为方法传递参数来指定经过的时间,此时该方法的作用与Sleep相类似,执行经过多长时间后来执行被插入的线程。Join方法的灵活运行能够实现线程之间的执行顺序。

  1. using System;  
  2. using System.Threading;  
  3.   
  4. namespace TestJoin  
  5. {  
  6.     
  7.     
  8.     
  9.     class Program  
  10.     {  
  11.         static void Main(string[] args)  
  12.         {  
  13.             
  14.             Thread t1 = new Thread(() =>  
  15.             {  
  16.                 Thread.Sleep(1000);  
  17.                 Console.WriteLine("t1 is ending.");  
  18.             });  
  19.             t1.Start(); 
  20.   
  21.             t1.Join();  
  22.             Console.WriteLine("t1.Join() returned.");   
  23.   
  24.   
  25.             
  26.             Thread t2 = new Thread(() =>  
  27.             {  
  28.                 Thread.Sleep(1000);  
  29.                 Console.WriteLine("t2 is ending.");  
  30.             });  
  31.             t2.Start(); 
  32.   
  33.             Console.WriteLine("t2.Join() returned.");   
  34.             Console.ReadLine();  
  35.         }  
  36.     }  
  37. }  

     输出结果:
               

         从输出结果上分析可以得出,Join方法将创建的线程插入到了主线程中当执行完后再继续执行主线程,对应到Demo2中是线程t1插入到了主线程中,这样会首先执行t1线程在控制台上打印“t1 is ending”打印完成后t1线程结束,然后继续执行主线程来打印其它的文字。所以我们完全可以说Join方法是将一个线程插入到主线程中,当执行完插入的线程后再继续执行被插入的线程。

结语

      线程的优缺点决定了在开发过程中是否使用多线程,另外灵活运行单线程的方法来实现灵活的控制线程,两个Demo使用了线程的基本方法,能够更加深刻的了解它们的使用。下篇博客将会更加深入的讨论线程和线程之间的调用关系,以及如何实现线程间的数据传递及检索。