c#多线程之旅——介绍和基本概念

author author     2022-08-31     698

关键词:

 

原文地址:C#多线程之旅(1)——介绍和基本概念

C#多线程之旅目录:

C#多线程之旅(1)——介绍和基本概念

C#多线程之旅(2)——创建和开始线程

C#多线程之旅(3)——线程池

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

C#多线程之旅(5)——同步机制介绍

C#多线程之旅(6)——详解多线程中的锁

更多文章正在更新中,敬请期待......

C#多线程之旅(1)——介绍和基本概念

一、多线程介绍

C#通过多线程支持并行执行的代码。一个线程是一个独立执行的路径,可以同时与其他线程一起运行。一个C#客户端程序(Console,WPF,Winows Forms)开始于一个单独的线程,该线程由CLR和操作系统自动地创建,我们称它为主线程,而且可以通过创建附加的线程来实现多线程。

所有的例子都假设引入了以下的namespaces

Using System;

Using System.Threading;

1.初探

技术分享
 1  class Program
 2 {
 3             static void Main(string[] args)
 4             {
 5                 Thread thread = new Thread(WriteY);//创建一个线程
 6                 thread.Start();//开始一个线程
 7     
 8                 for (int i = 0; i < 1000; i++)//主线程执行循环
 9                 {
10                     Console.Write("x");
11                 }
12     
13                 Console.ReadLine();
14             }
15             static void WriteY()
16             {
17                 for (int i = 0; i < 1000; i++)
18                 { 
19                     Console.Write("y"); 
20                 }
21             }
22 
23     }
技术分享

技术分享

 

 技术分享

 

一旦开始,一个线程的IsAlive属性返回true,直到这个线程结束。当传递给线程的构造函数的委托完成执行时,这个线程结束。一旦结束,这个线程不能重启。

2.内存隔离

CLR给每个线程分配自己内存栈,因此局部变量可以保持分离。在下一个例子中,我们定义了一个

使用局部变量的方法,然后在主线程和子线程同时调用这个方法。

技术分享
 1 class Program
 2 {
 3     static void Main(string[] args)
 4     {
 5         new Thread(Go).Start();
 6         Go();
 7         Console.ReadKey();
 8     }
 9 
10     static void Go()
11     {
12         for (int i = 0; i < 5; i++)
13         {
14             Console.Write("y");
15         }
16     }
17 }
技术分享

 

技术分享

因为每个线程的内存栈都有一份隔离的循环变量的拷贝,因此可以推断出,输出结果是10个“y”字符 

3.数据共享

如果多个线程对同一个对象实例有相同的引用,这些线程就共享这个对象实例的数据。例如:

技术分享
 1 class Program
 2 {
 3     bool done = false;
 4     static void Main(string[] args)
 5     {
 6         Program p= new Program();
 7         new Thread(p.Go).Start();
 8         p.Go();
 9         Console.ReadKey();
10     }
11 
12     void Go()
13     {
14         if (!done)
15         {
16             done = true;
17             Console.WriteLine("Done");
18         }
19     }
20 }
技术分享

 

技术分享

因为两个线程都调用实例pgo的方法,因此他们共享done这个字段,结果是done只打印出一次而不是两次。

静态字段提供另外一种共享数据的方法:

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

4.线程安全

这两个例子展示了另外一个重要的概念:线程安全确实是不确定的:done可能被打印出两次(尽管是不太可能发生的)。当我们把Go方法中的语句的顺序交换下,打印出两次done的几率显著提升。

技术分享
 1 class Program
 2 {
 3     static bool done = false;
 4     static void Main(string[] args)
 5     {
 6         Program p = new Program();
 7         new Thread(p.Go).Start();
 8         p.Go();
 9         Console.ReadKey();
10     }
11 
12     void Go()
13     {
14         if (!done)
15         {
16             Console.WriteLine("Done");
17             done = true;
18         }
19     }
20 }
技术分享

 

技术分享

这个地方的问题是线程A在线程B设置done等于true之前进入if条件判断中,所有A有机会打印出"Done"

改进方式当读写一个公共字段时,获取一个独占锁(exclusive lock)。C#提供了关键字lock

技术分享
 1 class Program
 2 {
 3     static bool done = false;
 4     static readonly object locker = new object();
 5     static void Main(string[] args)
 6     {
 7         new Thread(Go).Start();
 8         Go();
 9         Console.ReadKey();
10     }
11 
12     static void Go()
13     {
14         lock (locker)
15         {
16             if (!done)
17             {
18                 Console.WriteLine("Done");
19                 done = true;
20             }
21         }
22     }
23 }
技术分享

技术分享

当两个线程同时抢占一个锁时(在这个例子中,locker,一个线程等待,或者阻塞,知道这个锁释放。在这个例子中,这个锁保证一次只有一个线程可以进入代码的临界区域,然后“Done”只会被打印一次。代码在这种不确定的多线程背景下中被保护被叫做线程安全。

注意:在多线程中,共享数据是造成复杂原因的主要,而且会产生让人费解的错误。尽管很基本但还是要尽可能保持简单。

一个线程,当阻塞的时候,不占用CPU资源。

二、Join Sleep

1.Join

通过调用一个线程的Join方法,可以等待另外一个线程结束。例如:

按 Ctrl+C 复制代码
按 Ctrl+C 复制代码

 

这个会打印字符"y"1000次,然后紧接着立刻打印"Thread t has ended!"Join有多个重载方法,可以在Join方法中添加一个参数,milliseconds或者timeSpan。如果这个线程结束了则Join方法返回true,如果这个线程超时则返回false

2.Sleep

Thread.Sleep暂停当前线程一段指定的时间:

Thread.Sleep(TimeSpan.FromHours(1));//sleep一个小时

Thread.Sleep(500);//sleep 500 微秒

当使用SleepJoin暂停线程时,这个线程是阻塞的,不消耗CPU资源。

Thread.Sleep(0)立即放弃这个线程的时间片,主动交出CPU给其他线程。Framework 4.0的新方法Thread.Yield()方法做同样的事,除了当它仅仅在同一个进程中时,才会放弃时间片。

Sleep(0)Yield()有时候对提升产品性能有用。而且它们也是诊断工具可以帮助揭开线程安全的问题;

如果在代码中的任何地方都插入Thread.Yield(),会造成bug

 

三、线程怎样工作

1.多线程由一个线程调度器来进行内部管理,一个功能是CLR常常委托给操做系统。

一个线程调度器确保所有激活的线程在执行期间被合适的分配,等待或者阻塞的线程(比如,一个独占锁或者等待用户输入)不占用CPU资源。

2.在单核电脑上,一个线程调度器让时间片在每一个激活的线程中切换。在windows操作系统下,线程切换的时间分片通常为10微秒,远远大于CPU的开销时间(通常小于1微秒)。

3.在一个多核的电脑上,多线程实现了一个混合的时间片和真正的并发,不同的线程同时在不同的CPU上执行代码。还是存在某些时间片,因为操作系统需要服务它自己的线程,包括其他的应用的线程。

4.当一个线程的执行被内部因素打断,比如时间片,则说这个线程是抢占式的。在大部分情形下,一个线程不能控制自己何时何地被抢占。

四、线程和进程

一个线程类似于你的应用程序正在运行的一个操作系统进程。类似于进程并行运行在一台电脑上,线程并行运行在一个单独的进程中。进程之间是完全隔离的;线程在一定程度上隔离。运行在同一个应用程序下的线程共享堆内存。在某种程度上,这就是为什么线程如此有用:一个线程可以在后台取回数据,比如同时另外一个线程正在显示数据。

五、线程的使用和误用

多线程有许多用途,下面是最通用的:

保持一个可响应的用户界面

通过在一个并行的“worker”线程上运行时间消耗的任务,主UI线程可以空闲地执行键盘或鼠标事件。

使其他阻塞CPU的线程得到最有效的使用

当一个线程正等待另外一计算机或硬件的响应时是非常有用的。当一个线程执行任务时阻塞了,其他线程正好可以使用计算机。

并行编程

如果工作负荷被共享给正在执行“各个击破”策略的多个线程,则代码在多核或多进程中集中计算可以执行得更快。

预测执行

在多核的机器上,你有时通过预测某些事情需要做,然后提前做,从而可以提高性能。LINQPad使用这项技术提高查询的创建。一个变体是运行许多并行的算法去处理同样的任务。无论哪个完成了第一个“wins-当你预先不知道哪一个算法执行得更快时,这是非常有效的。

允许同时执行请求

在一个server上,客户端请求可以并行抵达,所以需要并行处理。如果你使用ASP.NET,WCF,Web ServiceRemoting.NET Framework 会自动创建线程。这个在client上也是有用的(比如说处理点对点的net working,或者是user的多个请求)。

比如ASP.NETWCF技术,你可能甚至不会注意到,除非你访问没有合适的locking,违反线程安全的共享数据(假定通过静态字段)。

多线程会带来一系列问题。最大的问题是多线程会提升复杂性。有许多线程本身不会带来复杂性,而是因为线程之间的相互影响(尤其是通过共享数据)。这个适用于是否这个相互影响是故意的,而且这个可以造成长时间的开发周期和一个持续性的敏感性和不可重现的bug。因为这个原因,需要将相互影响降到最低。尽可能坚持和提高可靠的设计。这篇文章主要集中在处理这些复杂性,移除相互影响这个不用多说。

一个好的策略是封装多线程的logic到可复用的类中,这些类可以独立地被测试。这个Framework它自己提供了许多的高级线程构造函数,我们后面再介绍。

线程在调度和切换线程时会造成资源和CPU的消耗(当激活的线程数量多余CPU的核的数量时)-而且有创建/销毁损耗。多线程通常会提升应用程序的速度-但是如果过度或者不适当使用甚至会使应用程序变慢。比如,当硬件I/O被涉及到时,有两个线程串行运行任务比起10个并行线程一次性执行更快。(在等待和脉冲信号中,我们描述怎样实现一个生产者/消费者队列来实现这个功能。)

c#多线程之旅

...地址:https://github.com/Jackson0714/Threads 原文地址:C#多线程之旅(4)——APM初探C#多线程之旅目录:C#多线程之旅(1)——介绍和基本概念C#多线程之旅(2)——创建和开始线程C#多线程之旅(3)——线程池C#多线程之旅(4)——APM初探C#多... 查看详情

c#多线程之旅

阅读目录代码下载一、介绍二、通过TPL进入线程池三、不用TPL进入到线程池v博客前言先交代下背景,写《C#多线程之旅》这个系列文章主要是因为以下几个原因:1.多线程在C/S和B/S架构中用得是非常多的;2.而且多线程的使用是非... 查看详情

c#之多线程--任务概念以及使用示例(task|taskcompletionsource|async|await)(代码片段)

C#之异步多线程任务相关以及概念使用介绍一,相关关键字和运算符1.1Async/Await介绍和使用示例1.2Async/Await异步编程中的最佳做法二,Task类2.1Task定义2.2属性方法1.3Task使用三,TaskCompletionSource类3.1概念定义3.2属性函数3.3模拟... 查看详情

c#进阶c#多线程(代码片段)

...0【C#进阶】C#泛型21【C#进阶】C#匿名方法文章目录前言1、线程与多线程的基本概念2、创建并使用线程3、检索线程对象4、前台线程和后台线程5、Thread类的属性和方法结语前言🐪hello大家好,我是哈桑c,本文为大家介... 查看详情

c#多线程

...程序的一个运行例程,是应用程序的一次动态执行过程。线程(Thread 查看详情

菜鸟之旅——学习线程(线程和线程池)(代码片段)

愉悦的绅士 菜鸟之旅——学习线程(线程和线程池)  上一篇主要介绍了进程和线程的一些基本知识,现在回归正题,我们来学一下线程的使用,本篇主要是使用新建线程和线程池的方式。线程    先来介绍简单的线... 查看详情

java高级编程--多线程

多线程程序将单个任务按照功能分解成多个子任务来执行,每个子任务称为一个线程,多个线程共同完成主任务的运行过程,这样可以缩短用户等待时间,提高服务效率。本篇博客将简单介绍Java开发中多线程的使用。目录:?程... 查看详情

kafka技术之旅kafka的基本原理及介绍

kafka架构与原理Kafka的介绍和历史Kafka是最初由Linkedin公司开发,是一个分布式(Distribute)、分区(Partition)的、多副本(Replica)的、多生产者(Producer)、多订阅者(Consumer)。最初是基于zookeeper协调的分布式日志系统(也可以当做MQ系... 查看详情

python对比线程,进程,携程,异步,哪个快

目录概念介绍测试环境开始测试测试【单进程单线程】测试【多进程并行】测试【多线程并发】测试【协程+异步】结果对比绘图展示概念介绍首先简单介绍几个概念:进程和线程进程就是一个程序在一个数据集上的一次动态执... 查看详情

fdsfsdfsdfsdfsdf

java基本运算各种运算符用法等进位二进制左移右移多线程基础多线程进阶线程池java原子性操作等基础java的concurrent包以及各种java自带系统属性的理解和应用volitaleSynchronizedReentrantLocktransientjava的锁15种锁的分类和理解等信息javaiob... 查看详情

java多线程——基本概念

...操作系统申请资源(如内存空间和文件句柄)的基本单位。线程(thread):进程中可独立执行的最小单位。一个进程可以包含多个线程,同一个进程中的所有线程共享该进程中的资源。Java平台中的一个线程就是一个对象。任务(task):... 查看详情

c#中构建多线程应用程序

...言  随着双核四核等多核处理器的推广多核处理器或超线程单核处理器的计算机已很常见基于多核处理的编程技术也开始受到程序员们普遍关注这其中一个重要的方面就是构建多线程应用程序(因为不使用多线程的话开发人员... 查看详情

09_1_线程的基本概念

09_1_线程的基本概念1. 线程的基本概念线程的一个程序内部的顺序控制流。线程和进程的区别每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。线程可以看成是轻量级的进程,同一类线程共享... 查看详情

docker之旅-基本概念-02

基本概念Docker包括三个基本概念镜像(Image)容器(Container)仓库(Repository)理解了这三个概念,就理解了Docker的整个生命周期。Docker镜像我们都知道,操作系统分为内核和用户空间。对于Linux而言,内核启动后,会挂载 root... 查看详情

c++11多线程第一篇:并发基本概念及实现,进程线程基本概念

文章目录1、并发基本概念及实现,进程、线程基本概念1.1并发、进程、线程的基本概念和综述1.1.1并发、并行1.1.2可执行程序1.1.3进程1.1.4线程1.1.5程序、进程、线程1.1.6学习心得1.2线程概念讲解1.2.1什么是线程1.2.2线程的优点1.... 查看详情

中央处理器-第七节2:硬件多线程的基本概念

文章目录一:细粒度多线程二:粗粒度多线程三:同时多线程硬件多线程:在(王道408考研操作系统)第二章进程管理-第一节5:线程概念和多线程模型这一节中我们说到了线程的一些缺点。线程粒度较进程来讲更细,而且线程切... 查看详情

并发编程-内存模型

在C++1x标准中,一个重大的更新就是引入了C++多线程内存模型。本文的主要目的在于介绍C++多线程内存模型涉及到的一些原理和概念,以帮助大家理解C++多线程内存模型的作用和意义。 1.顺序一致性模型(SequentialConsistency)在介... 查看详情

初学java多线程的基本概念

一:线程与之前所学的进程区别:进程:系统进行资源分配的最小单位,资源是独立的线程:CPU调度的最小的单位,线程间共享资源。多线程几个线程共占据一个进程,单线程独占一个线程。主线程就像是前台接待,当工作量太... 查看详情