c# 多线程 执行事件 并发_C#.NET Thread多线程并发编程学习与常见面试题解析-1、Thread使用与控制基础...
因為平時挺少用到多線程的,寫游戲時都在用協(xié)程,至于協(xié)程那是另一個話題了,除了第一次學(xué)習(xí)多線程時和以前某個小項目有過就挺少有接觸了,最近準(zhǔn)備面試又怕被問的深入,所以就趕緊補補多線程基礎(chǔ)。
網(wǎng)上已經(jīng)有很多線程編程的學(xué)習(xí)筆記了,那我為什么還要再整理一篇呢。因為我在搜索網(wǎng)上文章的時候發(fā)現(xiàn)一般別人整理的面試文章那很多語法都一筆帶過了默認(rèn)大家都懂,學(xué)習(xí)文章又很少有給出經(jīng)典的題目,一般都是要幾篇集合著一起看,既然如此的話我為什么不自己整理出一份呢?自己看的輕松,說不定以后也有人喜歡這種風(fēng)格能幫助到別人。所以這篇文章也會參考很多其他的文章,最后都會寫上引用的。
我寫算法的時候也是很喜歡用C++ 來學(xué)習(xí),而且筆試的時候我或者很多公司也喜歡用C++,畢竟C++ 的控制臺程序輸入輸出格式化做的也比較好,那為什么這篇又用的是C#而不是C++ 呢?因為最近實習(xí)只帶著筆記本,我的筆記本上只裝了vscode用來寫輕量級程序?qū)W習(xí)。C++裝的是MinGW來編譯,但是MinGW因為跨平臺吧對std::thread支持的又不太好,反正又不是不會用別的語言,最重要的是學(xué)習(xí)的思想嘛。
一、進(jìn)程和線程有什么區(qū)別?為什么要使用多線程?
首先用最經(jīng)典的一道面試題作為引入。
①進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位。
②一個線程只能屬于一個進(jìn)程,而一個進(jìn)程可以有多個線程。
③進(jìn)程在執(zhí)行過程中擁有獨立的內(nèi)存單元,而多個線程共享進(jìn)程的內(nèi)存。
④進(jìn)程間不會相互影響 ;線程一個線程掛掉將導(dǎo)致整個進(jìn)程掛掉。
⑤進(jìn)程編程調(diào)試簡單可靠性高,但是創(chuàng)建銷毀開銷大;線程正相反,開銷小,切換速度快,但是編程調(diào)試相對復(fù)雜。
⑥部分任務(wù)可能比較耗時,長時間占用CPU(你肯定不希望應(yīng)用執(zhí)行某個功能時整個程序都卡死),如果創(chuàng)建進(jìn)程解決可能額外CPU開銷更大,因此部分時候需要使用多線程技術(shù)。
二、C# 中使用多線程
在 C# 中,System.Threading.Thread 類用于線程的工作。它允許創(chuàng)建并訪問多線程應(yīng)用程序中的單個線程。進(jìn)程中第一個被執(zhí)行的線程稱為主線程。 當(dāng) C# 程序開始執(zhí)行時,主線程自動創(chuàng)建使用 Thread 類創(chuàng)建的線程被主線程的子線程調(diào)用。
再介紹Thread類中比較有用的一個靜態(tài)方法,Sleep,用于掛起(可以看成暫停)線程一段時間,參數(shù)是毫秒。
下面來一個簡單的例子看Thread的使用:
執(zhí)行該程序首先暫停1秒(1000毫秒),接著連續(xù)輸出 我是不帶參數(shù)的線程我是帶參數(shù)的線程
然后再暫停1秒,接著輸出我是不帶參數(shù)的線程
一開始是在主線程中掛起(暫停)的,所以兩個線程都要等1秒才執(zhí)行,后面是在不帶參數(shù)的線程中掛起的,不影響另一個線程,所以帶參數(shù)的線程就直接輸出了。
但是要注意的是我這里是在Thread直接指定了方法,但實際上該方法有委托類型
所以說剛剛的實例化可以展開成如下形式
Thread這里的參數(shù)用的是object,有可能會被問到一個問題就是拆箱裝箱,當(dāng)然拆箱裝箱和之前提的委托,包括什么匿名函數(shù)、lambda之類的都是另一個話題了,這里為了保持知識的獨立性不過多的引入其他特性了,只在必要的時候講。
三、資源搶占與信號
上面的內(nèi)容十分簡單,似乎跟普通的實例化類調(diào)用下函數(shù)沒什么區(qū)別啊。
那我們再用一道面試題作為引入:
兩個線程交替打印0~100的奇偶
如果只用上面的知識寫出下面的代碼,那運行一下就可以發(fā)現(xiàn)問題所在了。
using結(jié)果:
當(dāng)然這個結(jié)果不一定是一樣的,畢竟是兩個線程并發(fā)在跑,但是卻只有一個控制臺啊,當(dāng)然,往深一點說就是多個線程共享的資源。
就像十字路口如果不控制車輛開動的順序,仍由他們亂開會引發(fā)嚴(yán)重的后果一樣,實際上我們在編程中也經(jīng)常會遇到控制線程順序的需求。
那說到這其實也很好理解了,就跟十字路口需要紅綠燈一樣,我們也會用到信號燈的思想去控制線程的執(zhí)行順序。
在C#中有封裝好類EventWaitHandle(并不嚴(yán)謹(jǐn),下期說,這期是為了方便理解概念),有幾個成員方法,
WaitOne():如果是紅燈的話會將線程暫停在當(dāng)前位置。
Set():相當(dāng)于開綠燈,允許被暫停的線程通過開始執(zhí)行下面的代碼了
Reset():相當(dāng)于開紅燈,線程遇到wait會暫停住。
EventWaitHandle必須指定一個枚舉類型,AutoReset或ManualReset,ManualReset很好理解,就是手動開關(guān)紅綠燈。而AutoReset是指在執(zhí)行Set()后會馬上自定執(zhí)行一次Reset(),相當(dāng)于只是把當(dāng)前在紅燈前的線程放行。
那么有了這些知識我們就可以開始寫代碼了
當(dāng)然,這里寫成開了兩個flag完全是為了方便理解,事實上可以只開一個叫flag,然后把evenFlag和oddFlag都改成flag,畢竟只有兩個線程,要么停要么走嘛。
最后我們似乎能把兩個函數(shù)再合成成為一個函數(shù),但是這樣的話單單一個信號燈似乎是沒辦法解決的了,可以像上面用兩個信號量或者下篇還有機會出來的話講講鎖。
引用:
.NET面試題解析(07)-多線程編程與線程同步-/夢里花落知多少/
Thread Class-MSDN
C#多線程-菜鳥教程
EventWaitHandle Class-MSDN
多線程C#面試題-Ax0ne
總結(jié)
以上是生活随笔為你收集整理的c# 多线程 执行事件 并发_C#.NET Thread多线程并发编程学习与常见面试题解析-1、Thread使用与控制基础...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 商业 AI 图像生成服务 Midjour
- 下一篇: OPPO Find X6 Pro将支持W