C#线程--5.0之前时代(一)--- 原理和基本使用
一、開篇概念明晰:
多任務(wù):
- 協(xié)作式多任務(wù):cpu可以處理多種任務(wù),但是這些任務(wù)是排隊(duì)等候的,當(dāng)cpu在處理一個(gè)任務(wù)的時(shí)候,其他的任務(wù)被鎖定,只有當(dāng)cpu處理完當(dāng)前任務(wù),才可以繼續(xù)處理下一個(gè)任務(wù)(專一暖男);
- 搶占式多任務(wù):一個(gè)任務(wù)正在執(zhí)行,可以被強(qiáng)行中斷掛起,去執(zhí)行其他的任務(wù)(花心大蘿卜)。
進(jìn)程與線程:
- 進(jìn)程:內(nèi)存和資源的物理分離成為進(jìn)程。分配給進(jìn)程的內(nèi)存只有所屬的進(jìn)程才可以訪問(wèn)。一個(gè)應(yīng)用程序可以啟動(dòng)多個(gè)進(jìn)程
- 線程:開發(fā)架構(gòu)將程序中的一部分進(jìn)行分離,使被分離的部分與程序的其余部分執(zhí)行順序不一致的操作。(在計(jì)算機(jī)中,程序的運(yùn)行時(shí)由程序計(jì)數(shù)器決定的,程序計(jì)數(shù)器就像是一個(gè)指針,指定了應(yīng)用程序下一步需要執(zhí)行的指令。)
- 進(jìn)程與線程:一個(gè)進(jìn)程啟動(dòng),默認(rèn)會(huì)有一個(gè)主線程,但是一個(gè)進(jìn)程可以對(duì)應(yīng)多個(gè)線程。
- 時(shí)間片:處理器分配給線程的執(zhí)行時(shí)間。一個(gè)處理器一次只能處理一個(gè)線程,所謂的多任務(wù)(搶占式)就是處理器在快速切換執(zhí)行不同的線程。若是有多個(gè)處理器就不一樣了。(自我入宮以來(lái)以為可以獨(dú)得皇上寵愛,沒想到皇上要雨露均沾)。
中斷:
前置知識(shí)點(diǎn):
1、進(jìn)程是內(nèi)存和資源的物理分離,只有所屬線程才能訪問(wèn);
2、一個(gè)cpu給一次只能執(zhí)行一個(gè)線程,cpu給每一個(gè)線程分配時(shí)間片,多線程就是在不同線程之間快速切換。
問(wèn)題:進(jìn)程間相互獨(dú)立且不可訪問(wèn),那么,cpu是怎么進(jìn)行線程切換的,也就是問(wèn):一個(gè)線程正在執(zhí)行,它要怎么知道要中斷掛起,給其他線程來(lái)執(zhí)行。
答案:Windows本身(其實(shí)也是處理器上正在運(yùn)行的一個(gè)程序)有一個(gè)主線程----系統(tǒng)線程,負(fù)責(zé)其他線程的調(diào)度。
線程本地存儲(chǔ)器(Thread Local Storage,TLS):存儲(chǔ)線程的狀態(tài)信息。當(dāng)一個(gè)線程執(zhí)行的時(shí)間片到期的時(shí)候,需要存儲(chǔ)下線程當(dāng)前的狀態(tài)信息,以確保在他被分配的下一個(gè)時(shí)間片可以正常的執(zhí)行。TLS包含了:
寄存器、堆棧指針、調(diào)度信息、內(nèi)存中的地址空間和其他資源的使用信息。
其中寄存器中有一個(gè)是程序計(jì)數(shù)器,存放了線程接下來(lái)應(yīng)該執(zhí)行的指令。(CPU執(zhí)行的指令的都是從寄存器讀取的)
中斷:中斷是一種機(jī)制,它能夠使CPU指令的正常順序執(zhí)行轉(zhuǎn)向計(jì)算機(jī)內(nèi)存中的其他地方,而不需要知道目前正在執(zhí)行什么程序。解釋如下:
1、程序要開始執(zhí)行一個(gè)線程之前:系統(tǒng)線程先決定線程要執(zhí)行多長(zhǎng)時(shí)間,and在當(dāng)前線程的執(zhí)行序列中放置一條中斷指令。疑問(wèn):不確定這個(gè)指令是在時(shí)間片到了之后插入的還是在線程開始之前預(yù)先插入的,但推測(cè)是等待時(shí)間片要到的時(shí)候插入的,因?yàn)槌绦驁?zhí)行的指令并不是容易預(yù)測(cè)的,不同的數(shù)據(jù)不同走不同的邏輯分支,程序的執(zhí)行是一邊編一邊走的(會(huì)先編譯的快一些)而不是編譯好所有的邏輯分支的指令,等待程序執(zhí)行的時(shí)候根據(jù)數(shù)據(jù)進(jìn)行選擇,所以個(gè)人覺得很難預(yù)測(cè)要走哪一個(gè)邏輯分支,很難提前太早插入中斷指令。
2、程序開始執(zhí)行一個(gè)線程:讀取TLS中線程的程序計(jì)數(shù)器,把該程序計(jì)數(shù)器的指令指向的地址從TLS中拖拽出來(lái)插入到CPU執(zhí)行的指令集合中,同時(shí)把TLS中的堆棧信息加載到CPU的其他寄存器中。線程開始執(zhí)行
3、當(dāng)碰到中斷指令時(shí):存儲(chǔ)當(dāng)前線程的堆棧信息,記錄當(dāng)前線程的程序計(jì)數(shù)器數(shù)據(jù),記錄其他資源的信息,存儲(chǔ)入TLS,把當(dāng)前線程放入線程隊(duì)列的末尾,返回到線程隊(duì)列的開頭準(zhǔn)備執(zhí)行隊(duì)列的第一個(gè)線程,回到步驟1。
線程睡眠:線程退出執(zhí)行隊(duì)列一段時(shí)間稱為睡眠。有時(shí)一個(gè)線程的執(zhí)行需要一定的資源,但是當(dāng)線程開始執(zhí)行時(shí),這個(gè)資源并沒有生成或者正在被使用,因此線程需要等待一段時(shí)間。
時(shí)鐘中斷:一個(gè)線程進(jìn)入睡眠是它會(huì)再次被打包放入TLS中,不過(guò)并不是放置在了TLS的末尾,而是放入了一個(gè)獨(dú)立的睡眠隊(duì)列中,為了時(shí)睡眠隊(duì)列上的線程再次運(yùn)行,需要使用另一種中斷了標(biāo)記他們,成為時(shí)鐘中斷。當(dāng)一個(gè)睡眠的線程可以執(zhí)行的時(shí)候,它才會(huì)被放入到可運(yùn)行的線程隊(duì)列中,的末尾。
?線程終止:
線程終止時(shí),線程的TLS會(huì)釋放其內(nèi)存。
?
二、線程的創(chuàng)建:
直接貼代碼:
1、創(chuàng)建線程:
2、使用線程創(chuàng)建線程:
public override void DoExecute(){base.DoExecute();Thread mainThread = new Thread(new ThreadStart(MainThread));AddLog("current main thread's state is " + mainThread.ThreadState);mainThread.Start();AddLog("current main thread's state is " + mainThread.ThreadState);}private void FirstThread(){AddLog("FirstThread start~");for (int i = 0; i < 100; i++){AddLog("FirstThread index~ "+i);}AddLog("FirstThread stop~");}private void ThecondThread(){AddLog("ThecondThread start~");for (int i = 100; i < 200; i++){AddLog("ThecondThread index~ " + i);}AddLog("ThecondThread stop~");}private void MainThread(){AddLog("MainThread start~");Thread firstThread = new Thread(new ThreadStart(FirstThread));Thread secondThread = new Thread(new ThreadStart(ThecondThread));firstThread.Start();secondThread.Start();for (int i = 0; i < 100000; i++){}AddLog("thecondThread state " + secondThread.ThreadState);AddLog("MainThread stop~");}?3、線程的睡眠和恢復(fù):
使用屬性:
ThreadState:ThreadState是一個(gè)枚舉類型,表示線程的當(dāng)前狀態(tài),當(dāng)線程睡眠的時(shí)候線程狀態(tài)值為ThreadState.WaitSleepJoin;
?注意一個(gè)類似的屬性:IsAlive (獲取指示當(dāng)前線程的執(zhí)行狀態(tài)的值)如果此線程已經(jīng)開始但尚未正常終止或中止,則為 true,否則為 false。所以當(dāng)線程睡眠的時(shí)候,isAlive仍然為true;
使用方法:
- Sleep(int millisecondsTimeout);? ?millisecondsTimeout表示使線程睡眠的毫秒數(shù);
- Interrupt();? ? ? 中斷處于 WaitSleepJoin 線程狀態(tài)的線程。
?測(cè)試代碼:
public static void SleepThread(){Thread newThread = new Thread(new ThreadStart(PrintNo));newThread.Name = "new thread";newThread.Start();while (true){if (newThread.ThreadState == ThreadState.WaitSleepJoin){Console.WriteLine("current thread state: " + newThread.ThreadState);newThread.Interrupt();break;}}}static void PrintNo(){for (int i = 0; i < 99; i++){Console.WriteLine("print " + i);if (i == 90){//try {Thread.Sleep(2000);}catch (Exception ex){Console.WriteLine("new thread interrupted"+ex.Message);}Console.WriteLine("current thread is " + Thread.CurrentThread.Name + ", state: " + Thread.CurrentThread.ThreadState);}}}
結(jié)果:
... print 81 print 82 print 83 print 84 print 85 print 86 print 87 print 88 print 89 print 90 current thread state: WaitSleepJoin new thread interrupted current thread is new thread, state: Running print 91 print 92 print 93 print 94 print 95 print 96 print 97 print 98Interrupt() 是對(duì)睡眠的線程提前喚醒的最好方法,需要注意的是使用這個(gè)方法會(huì)拋出異常需要捕獲。
4、線程的中止(終止)和取消中止(終止):
使用方法:
- Thread.CurrentThread.Abort(); 終止當(dāng)前線程 --- 調(diào)用該方法線程將進(jìn)入正在終止?fàn)顟B(tài) ------? AbortRequested,
- Thread.ResetAbort();? 取消當(dāng)前線程Abort的請(qǐng)求使線程繼續(xù)執(zhí)行。調(diào)用該方法線程將恢復(fù)
?
運(yùn)行結(jié)果:
。。。
print 87
print 88
print 89
print 90
current thread is new thread for abort, state: AbortRequested
new thread Aborted正在中止線程。
?如果取消上面對(duì) Thread.ResetAbort(); 的注釋,線程將不會(huì)終止,而是會(huì)繼續(xù)執(zhí)行。
?
5、使用join:
使用方法:join(),join是線程實(shí)例上的方法,當(dāng)調(diào)用該方法的時(shí)候調(diào)用該方法的線程實(shí)例將進(jìn)入WaitSleepJoin狀態(tài),直到當(dāng)前線程執(zhí)行完畢之后才開始繼續(xù)執(zhí)行線程實(shí)例所屬的線程。
(我感覺理解起來(lái)有點(diǎn)繞,意思就是:有兩個(gè)線程A和B,線程A需要在線程B之前執(zhí)行,那么可以使用Join方法,在線程A內(nèi)用線程B調(diào)用Join方法,這樣可以使線程B進(jìn)入WaitSleepJoin狀態(tài),線程A不變繼續(xù)執(zhí)行,當(dāng)線程A執(zhí)行完畢,B會(huì)開始執(zhí)行。而如果有線程C,則線程C是不影響的)如下所示:
運(yùn)行結(jié)果:
。。。 print 我是勤勞的小畫家 print 我是勤勞的小畫家 print 我是勤勞的小畫家 print 92 print 93 print 94 print 95 print 96 print 97 print 98 print 99 print 我是勤勞的小畫家 print 我是勤勞的小畫家 print 我是勤勞的小畫家 print 我是勤勞的小畫家 print 100 print 101 print 102 。。。?
轉(zhuǎn)載于:https://www.cnblogs.com/heisehenbai/p/9221444.html
總結(jié)
以上是生活随笔為你收集整理的C#线程--5.0之前时代(一)--- 原理和基本使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: centos下配置gitosis服务器
- 下一篇: Python windows安装MYSQ