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

前言:
因为平时挺少用到多线程的,写游戏时都在用协程,至于协程那是另一个话题了,除了第一次学习多线程时和以前某个小项目有过就挺少有接触了,最近准备面试又怕被问的深入,所以就赶紧补补多线程基础。
网上已经有很多线程编程的学习笔记了,那我为什么还要再整理一篇呢。因为我在搜索网上文章的时候发现一般别人整理的面试文章那很多语法都一笔带过了默认大家都懂,学习文章又很少有给出经典的题目,一般都是要几篇集合着一起看,既然如此的话我为什么不自己整理出一份呢?自己看的轻松,说不定以后也有人喜欢这种风格能帮助到别人。所以这篇文章也会参考很多其他的文章,最后都会写上引用的。
我写算法的时候也是很喜欢用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

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

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

相关文章

PWN-PRACTICE-BUUCTF-22

PWN-PRACTICE-BUUCTF-22hitcontraining_unlinkpicoctf_2018_leak_mesuctf_2018_basic pwnaxb_2019_brop64hitcontraining_unlink unlink&#xff0c;参考&#xff1a;[BUUCTF]PWN——hitcontraining_unlink # -*- coding:utf-8 -*- from pwn import * #ioprocess("./bam…

javaee, javaweb和javase的区别以及各自的知识体系

JavaSE Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类&#xff0c;并为 Java Platform&#xff0c;Enterprise Edition&#xff08;Java EE&#xff09;提供基础。 JavaE…

.NET 实现并行的几种方式(三)

在前两篇随笔中&#xff0c;先后介绍了 Thread 、ThreadPool 、IAsyncResult (即 APM系列) 、Task 、TPL (Task Parallel Library)。 写到这些笔者突然意识到 还有一个EMP系列没有写&#xff0c;在这里补充一下&#xff1a; 六、 EAP 、EAP中的典型代表是 WebClient: EAP系…

.NET异步编程之新利器——Task与Await、Async

一. FrameWork 4.0之前的线程世界     在.NET FrameWork 4.0之前&#xff0c;如果我们使用线程。一般有以下几种方式&#xff1a; 使用System.Threading.Thread 类&#xff0c;调用实例方法Start()开启一个新线程&#xff0c;调用Abort()方法来提前终止线程。使用System.T…

对比MS Test与NUnit Test框架

前言&#xff1a; 项目中进行Unit Test时&#xff0c;肯定会用到框架&#xff0c;因为这样能够更快捷、方便的进行测试。 .Net环境下的测试框架非常多&#xff0c;在这里只是对MS Test和NUnit Test进行一下比较&#xff0c; 因为这两个框架用的较多&#xff0c;也有大虾想过…

PWN-PRACTICE-BUUCTF-25

PWN-PRACTICE-BUUCTF-25wustctf2020_name_your_catciscn_2019_final_2mrctf2020_shellcode_revengezctf2016_note2wustctf2020_name_your_cat 通过数组越界覆写返回地址为后门shell的地址 from pwn import * #ioprocess(./wustctf2020_name_your_cat) ioremote(node4.buuoj.c…

使用 Github Pages 和 Hexo 搭建自己的独立博客【超级详细的小白教程】

2022-01-25 更新&#xff1a;博客新地址&#xff1a;https://www.itbob.cn/ 欢迎关注我的专栏&#xff1a;《个人博客搭建&#xff1a;HexoGithub Pages》&#xff0c;从搭建到美化一条龙&#xff0c;帮你解决 Hexo 常见问题&#xff01; 推荐阅读&#xff1a;《Hexo 博客优化…

windows程序消息机制(Winform界面更新有关)

1. Windows程序消息机制 Windows GUI程序是基于消息机制的,有个主线程维护着消息泵。这个消息泵让windows程序生生不息。 Windows程序有个消息队列&#xff0c;窗体上的所有消息是这个队列里面消息的最主要来源。这里的While循环使用了GetMessage() 这个方法,这是个阻塞方法,也…

最新主流 Markdown 编辑器推荐

Markdown &#xff0c;2004年由 John Gruberis 设计和开发&#xff0c;是一种可以使用普通文本编辑器编写的标记语言&#xff0c;通过简单的标记语法&#xff0c;它可以使普通文本内容具有一定的格式&#xff0c;以下将介绍目前比较流行的一些 Markdown 编辑器&#xff08;排名…

PWN-PRACTICE-BUUCTF-27

PWN-PRACTICE-BUUCTF-27starctf_2019_babyshellpicoctf_2018_buffer overflow 0gyctf_2020_signinbjdctf_2020_YDSneedGrirlfriendstarctf_2019_babyshell 用\x00绕过shellcode检测&#xff0c;call rdx 跳转过去执行汇编代码&#xff0c;一个\x00必执行失败 于是需要找一条机…

敏捷开发之Scrum扫盲,及敏捷开发中XP与SCRUM的区别

敏捷开发之Scrum扫盲篇 现在敏捷开发是越来越火了&#xff0c;人人都在谈敏捷&#xff0c;人人都在学习Scrum和XP... 为了不落后他人&#xff0c;于是我也开始学习Scrum&#xff0c;今天主要是对我最近阅读的相关资料&#xff0c;根据自己的理解&#xff0c;用自己的话来讲述S…

有关不蒜子访问统计无法显示的解决方法

十月初&#xff0c;不蒜子统计失效了&#xff0c;如下图&#xff1a; 进入不蒜子官网看看&#xff1a; 问题来了&#xff0c;官网写着&#xff1a;因七牛强制过期『dn-lbstatics.qbox.me』域名&#xff0c;与客服沟通无果&#xff0c;只能更换域名到『busuanzi.ibruce.info』…

SCRUM与XP区别

敏捷开发 1、敏捷的含义 敏捷开发是一种以人为核心、迭代、增量的开发方法。在敏捷开发中&#xff0c;把一个大项目分为多个相互联系&#xff0c;可独立运行的小项目&#xff0c;并分别完成&#xff0c;在此过程中软件一直处于可使用状态。 上面提到3个关键词&#xff0c;下…

Java编写程序时出现警告:Resource leak: 'xxx' is never closed 解决方案

菜鸟新手&#xff0c;学校在教Java&#xff0c;作业里面要求我们编程实现运算一个简单的程序&#xff0c;程序写好了&#xff0c;却发现冒出一个警告&#xff0c;如下图&#xff1a; 百度了一下&#xff0c;意思是申明了名为a的数据输入扫描仪&#xff08;Scanner&#xff09…

ASP.Net请求处理机制初步探索之旅 - Part 1 前奏

开篇&#xff1a;ASP.Net是一项动态网页开发技术&#xff0c;在历史发展的长河中WebForm曾一时成为了ASP.Net的代名词&#xff0c;而ASP.Net MVC的出现让这项技术更加唤发朝气。但是&#xff0c;不管是ASP.Net WebForm还是ASP.Net MVC在请求处理机制上大部分都是相同的&#xf…

ASP.Net请求处理机制初步探索之旅 - Part 2 核心

开篇&#xff1a;上一篇我们了解了一个请求从客户端发出到服务端接收并转到ASP.Net处理入口的过程&#xff0c;这篇我们开始探索ASP.Net的核心处理部分&#xff0c;借助强大的反编译工具&#xff0c;我们会看到几个熟悉又陌生的名词&#xff08;类&#xff09;&#xff1a;Http…

REVERSE-COMPETITION-0xGame2021

REVERSE-COMPETITION-0xGame2021Signin: User FriendlyInstallerOur Compilation StoryPacketRandom ChaosNeverlandRoundaboutDespacitoSecret BaseMazeZero ThreeMirrorThread_TLS茶谈室JunkertownSignin: User Friendly 64位exe&#xff0c;ida打开&#xff0c;在main函数中…

ASP.Net请求处理机制初步探索之旅 - Part 3 管道

开篇&#xff1a;上一篇我们了解了一个ASP.Net页面请求的核心处理入口&#xff0c;它经历了三个重要的入口&#xff0c;分别是&#xff1a;ISAPIRuntime.ProcessRequest()、HttpRuntime.ProcessRequest()以及HttpApplication.Init()。其中&#xff0c;在HttpApplication的Init(…

PWN-COMPETITION-GeekChallenge2021

PWN-COMPETITION-GeekChallenge2021check in恋爱小游戏ret2xxone恋爱小游戏2.0easyfmteasycanaryret2babypwn777check in 66s内解答200道四则运算的题目即可getshell 参与运算的数和运算符都会打印&#xff0c;直接写脚本即可 # -*- coding:utf-8 -*- from pwn import * cont…

ASP.Net请求处理机制初步探索之旅 - Part 4 WebForm页面生命周期

开篇&#xff1a;上一篇我们了解了所谓的请求处理管道&#xff0c;在众多的事件中微软开放了19个重要的事件给我们&#xff0c;我们可以注入一些自定义的业务逻辑实现应用的个性化设计。本篇&#xff0c;我们来看看WebForm模式下的页面生命周期。 &#xff08;1&#xff09;Par…