前言:
因为平时挺少用到多线程的,写游戏时都在用协程,至于协程那是另一个话题了,除了第一次学习多线程时和以前某个小项目有过就挺少有接触了,最近准备面试又怕被问的深入,所以就赶紧补补多线程基础。
网上已经有很多线程编程的学习笔记了,那我为什么还要再整理一篇呢。因为我在搜索网上文章的时候发现一般别人整理的面试文章那很多语法都一笔带过了默认大家都懂,学习文章又很少有给出经典的题目,一般都是要几篇集合着一起看,既然如此的话我为什么不自己整理出一份呢?自己看的轻松,说不定以后也有人喜欢这种风格能帮助到别人。所以这篇文章也会参考很多其他的文章,最后都会写上引用的。
我写算法的时候也是很喜欢用C++ 来学习,而且笔试的时候我或者很多公司也喜欢用C++,毕竟C++ 的控制台程序输入输出格式化做的也比较好,那为什么这篇又用的是C#而不是C++ 呢?因为最近实习只带着笔记本,我的笔记本上只装了vscode用来写轻量级程序学习。C++装的是MinGW来编译,但是MinGW因为跨平台吧对std::thread支持的又不太好,反正又不是不会用别的语言,最重要的是学习的思想嘛。


一、进程和线程有什么区别?为什么要使用多线程?

首先用最经典的一道面试题作为引入。
①进程是资源分配的最小单位,线程是CPU调度的最小单位。
②一个线程只能属于一个进程,而一个进程可以有多个线程。
③进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。
④进程间不会相互影响 ;线程一个线程挂掉将导致整个进程挂掉。
⑤进程编程调试简单可靠性高,但是创建销毁开销大;线程正相反,开销小,切换速度快,但是编程调试相对复杂。
⑥部分任务可能比较耗时,长时间占用CPU(你肯定不希望应用执行某个功能时整个程序都卡死),如果创建进程解决可能额外CPU开销更大,因此部分时候需要使用多线程技术。

二、C# 中使用多线程

在 C# 中,System.Threading.Thread 类用于线程的工作。它允许创建并访问多线程应用程序中的单个线程。进程中第一个被执行的线程称为主线程。 当 C# 程序开始执行时,主线程自动创建使用 Thread 类创建的线程被主线程的子线程调用。
再介绍Thread类中比较有用的一个静态方法,Sleep,用于挂起(可以看成暂停)线程一段时间,参数是毫秒。
下面来一个简单的例子看Thread的使用:

using System;
using System.Threading;
namespace LeeCarry
{public class Test{public static void Main(string[] args){Thread.Sleep(1000);//主线程暂停Thread npt=new Thread(NonParaThread);npt.Start();Thread wpt=new Thread(WithParaThread);wpt.Start("我是带参数的线程。");}private static void NonParaThread(){Console.WriteLine("我是不带参数的线程。");Thread.Sleep(1000);//子线程暂停Console.WriteLine("我是不带参数的线程。");}private static void WithParaThread(Object obj){Console.WriteLine(obj.ToString());}}
}

执行该程序首先暂停1秒(1000毫秒),接着连续输出 
我是不带参数的线程
我是带参数的线程
然后再暂停1秒,接着输出
我是不带参数的线程
一开始是在主线程中挂起(暂停)的,所以两个线程都要等1秒才执行,后面是在不带参数的线程中挂起的,不影响另一个线程,所以带参数的线程就直接输出了。
但是要注意的是我这里是在Thread直接指定了方法,但实际上该方法有委托类型

public delegate void ThreadStart()//用于无参数方法
public delegate void ParameterizedThreadStart(object obj) //用于有参数方法

所以说刚刚的实例化可以展开成如下形式

Thread npt=new Thread(new ThreadStart(NonParaThread));
Thread wpt=new Thread(new ParameterizedThreadStart(WithParaThread));

这里的参数用的是object,有可能会被问到一个问题就是拆箱装箱,当然拆箱装箱和之前提的委托,包括什么匿名函数、lambda之类的都是另一个话题了,这里为了保持知识的独立性不过多的引入其他特性了,只在必要的时候讲。

三、资源抢占与信号

上面的内容十分简单,似乎跟普通的实例化类调用下函数没什么区别啊。
那我们再用一道面试题作为引入:

两个线程交替打印0~100的奇偶

如果只用上面的知识写出下面的代码,那运行一下就可以发现问题所在了。

using System;
using System.Threading;
namespace LeeCarry
{public class Test{public static void Main(string[] args){Thread oddThread=new Thread(OddThread);Thread evenThread=new Thread(EvenThread);evenThread.Start(); oddThread.Start();}private static void EvenThread(){for(int i=0;i<=100;i+=2){Console.WriteLine("线程1:{0}",i);}}private static void OddThread(){for(int i=1;i<=100;i+=2){Console.WriteLine("线程2:{0}",i);}}}
}

结果:

当然这个结果不一定是一样的,毕竟是两个线程并发在跑,但是却只有一个控制台啊,当然,往深一点说就是多个线程共享的资源。
就像十字路口如果不控制车辆开动的顺序,仍由他们乱开会引发严重的后果一样,实际上我们在编程中也经常会遇到控制线程顺序的需求。

那说到这其实也很好理解了,就跟十字路口需要红绿灯一样,我们也会用到信号灯的思想去控制线程的执行顺序。
在C#中有封装好类EventWaitHandle(并不严谨,下期说,这期是为了方便理解概念),有几个成员方法,
WaitOne():如果是红灯的话会将线程暂停在当前位置。
Set():相当于开绿灯,允许被暂停的线程通过开始执行下面的代码了
Reset():相当于开红灯,线程遇到wait会暂停住。

EventWaitHandle必须指定一个枚举类型,AutoReset或ManualReset,ManualReset很好理解,就是手动开关红绿灯。而AutoReset是指在执行Set()后会马上自定执行一次Reset(),相当于只是把当前在红灯前的线程放行。
那么有了这些知识我们就可以开始写代码了

using System;
using System.Threading;
namespace LeeCarry
{public class Test{public static EventWaitHandle oddFlag=new EventWaitHandle(false,EventResetMode.AutoReset);public static EventWaitHandle evenFlag=new EventWaitHandle(false,EventResetMode.AutoReset);public static void Main(string[] args){Thread oddThread=new Thread(OddThread);Thread evenThread=new Thread(EvenThread);evenThread.Start(); oddThread.Start();}private static void EvenThread(){for(int i=0;i<=100;i+=2){Console.WriteLine("线程1:{0}",i);oddFlag.Set();evenFlag.WaitOne();}oddFlag.Set();//最后开一次绿灯防止线程一直被阻塞,也可以在waitone加时间参数}private static void OddThread(){oddFlag.WaitOne();//确保偶数线程先运行for(int i=1;i<=100;i+=2){Console.WriteLine("线程2:{0}",i);evenFlag.Set();oddFlag.WaitOne();}evenFlag.Set();//最后开一次绿灯防止线程一直被阻塞,也可以在waitone加时间参数}}
}

当然,这里写成开了两个flag完全是为了方便理解,事实上可以只开一个叫flag,然后把evenFlag和oddFlag都改成flag,毕竟只有两个线程,要么停要么走嘛。
最后我们似乎能把两个函数再合成成为一个函数,但是这样的话单单一个信号灯似乎是没办法解决的了,可以像上面用两个信号量或者下篇还有机会出来的话讲讲锁。


引用:

.NET面试题解析(07)-多线程编程与线程同步-/梦里花落知多少/

Thread Class-MSDN

C#多线程-菜鸟教程

EventWaitHandle Class-MSDN

多线程C#面试题-Ax0ne

C#.NET Thread多线程并发编程学习与常见面试题解析-1、Thread使用与控制基础相关推荐

  1. c# 多线程 执行事件 并发_C#.NET Thread多线程并发编程学习与常见面试题解析-1、Thread使用与控制基础...

    前言: 因为平时挺少用到多线程的,写游戏时都在用协程,至于协程那是另一个话题了,除了第一次学习多线程时和以前某个小项目有过就挺少有接触了,最近准备面试又怕被问的深入,所以就赶紧补补多线程基础. 网上已 ...

  2. 网易云课堂微专业--Java高级开发工程师--多线程并发编程--学习笔记(二)

    文章目录 第一章 多线程并发编程 第二节 线程安全问题 1.2.1 线程安全之可见性问题 多线程中的问题 从内存结构到内存模型 工作内存缓存 指令重排序 内存模型的含义 Shared Variable ...

  3. libevent c++高并发网络编程_高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  4. 高并发编程学习(2)——线程通信详解

    前序文章 高并发编程学习(1)--并发基础 - https://www.wmyskxz.com/2019/11/26/gao-bing-fa-bian-cheng-xue-xi-1-bing-fa-j ...

  5. Java高并发编程学习(三)java.util.concurrent包

    简介 我们已经学习了形成Java并发程序设计基础的底层构建块,但对于实际编程来说,应该尽可能远离底层结构.使用由并发处理的专业人士实现的较高层次的结构要方便得多.要安全得多.例如,对于许多线程问题,可 ...

  6. Java并发编程学习 + 原理分析(建议收藏)

    总结不易,如果对你有帮助,请点赞关注支持一下 微信搜索程序dunk,关注公众号,获取博客源码 Doug Lea是一个无私的人,他深知分享知识和分享苹果是不一样的,苹果会越分越少,而自己的知识并不会因为 ...

  7. java并发编程学习一

    java并发编程学习一 什么是进程和线程? 进程是操作系统进行资源分配的最小单位 进程跟进程之间的资源是隔离的,同一个进程之中的线程可以共享进程的资源. 线程是进程的一个实体,是CPU 调度和分派的基 ...

  8. java中解决脏读_java并发编程学习之脏读代码示例及处理

    使用interrupt()中断线程     当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一个标志,表示它已经被中断,并立即 ...

  9. python 多线程并发编程(生产者、消费者模式),边读图像,边处理图像,处理完后保存图像实现提高处理效率

    文章目录 需求 实现 先导入本次需要用到的包 一些辅助函数 如下函数是得到指定后缀的文件 如下的函数一个是读图像,一个是把RGB转成BGR 下面是主要的几个处理函数 在上面几个函数构建对应的处理函数 ...

最新文章

  1. 多用户使用一台计算机可设置,多用户使用一台计算机的情况经常出现,这时可设置()...
  2. Winform中自定义xml配置文件,并配置获取文件路径
  3. 数据库单表千万行 LIKE 搜索优化手记
  4. Neurocomputing 投稿注意事项
  5. 报告老板:这次的缓存事故是这样的...
  6. Linux之diff命令
  7. CentOS 8安装logrotate切割日志
  8. linux es数据库 head,Elasticsearch可视化插件ES-HEAD安装启动步骤
  9. date java format_java-DateFormat
  10. JAVA-jdk8的API文件下载
  11. 3500个常用汉字列表
  12. centos7使用iso镜像离线安装依赖工具
  13. Java 自定义Excel数据排序
  14. 【阅】天才在左 疯子在右
  15. 第四周:基于图像相似度比较的分镜头
  16. 美拍视频怎么下载?美拍视频解析下载和保存工具
  17. Date类型接收空字符串(@InitBinder注解实现)
  18. 计算机网络到底该怎么学?
  19. 开发Java程序的工具
  20. @Transactional 失效的几种情况

热门文章

  1. com.alibaba.fastjson.JSONObject cannot be cast to XXX异常解决
  2. 如何往eclipse中导入maven项目
  3. JAVA之运算符优先级
  4. Akka(19): Stream:组合数据流,组合共用-Graph modular composition
  5. DQL查询语句内容整理
  6. 我的20132014
  7. 云谊网-赴日人才社交网络
  8. C#提供的类库能够轻松实现对文件的操作
  9. VistaDB 数据库,.NET的新选择
  10. vue 获取请求url_vue 获取url里参数的两种方法小结