鎖之鎖的三種狀態及Monitor.Wait, Monitor.Pulse,Monitor.PulseAll的作用與用法

鎖之鎖的三種狀態及Monitor.WaitMonitor.PulseMonitor.PulseAll的作用與用法

目錄

1.線程鎖的三種狀態

2.Monitor.Wait,Monitor.Pulse的作用

3.Monitor.PulseAll的作用

4.總結(Q&A)

 

 

1.線程鎖的三種狀態

首先我們記住有有鎖線程的三種狀態:[持有鎖的線程],[就緒隊列],[等待隊列]

微軟官方文檔中英文截圖釋義如下[2][3]:

整理後中英文及釋義對照表如下:

中文

英文

釋義

[等待隊列]

waiting queue

線程運行到Wait處後狀態被改爲的等待隊列,需要進入就緒隊列纔拿到鎖

[就緒隊列]

ready queue

即將進入執行中的帶鎖的線程

[持有鎖的線程]

the thread that
currently holds the lock

執行中的帶鎖的線程

 

軟件中運行優先順序爲:

1.先運行 [持有鎖的線程] ,

2.然後是 [就緒隊列] 中排在最前的線程。

3.只有[等待隊列] 的線程進入[就緒隊列]纔有排隊資格,且排到最前纔會進入[持有鎖的線程]

需要注意:

1. 當前只能有一個線程狀態爲[持有鎖的線程]

2. 前一個線程釋放了鎖,纔可排到[就緒隊列]中最前的線程

3. 若[等待隊列]一直進入不了[就緒隊列]則一直不計入排隊序列

 

以超市購物爲例,

同個結賬窗口中:

1.當前窗口只能有一個客戶在結賬

2.只有前一個客戶結完賬後,排隊隊伍中排到最前的客戶纔可結賬

3.超市裏面排隊採購,排隊結賬,若不排隊則不能結賬

 

若結賬窗口是鎖,則:

1. [持有鎖的線程] 即  當前窗口結帳中的顧客(結賬中)

2. [就緒隊列]     即  排隊準備結賬的顧客們(排隊中)

3. [等待隊列]     即  仍在超市採購的顧客們(有順序的採購中)

2.Monitor.Wait,Monitor.Pulse的作用

前文已說過有鎖線程的三種狀態:[持有鎖的線程],[就緒隊列],[等待隊列]

 

軟件中運行優先順序爲:

1.先運行 [持有鎖的線程] ,

2.然後是 [就緒隊列] 中排在最前的線程。

3.只有[等待隊列] 的線程進入[就緒隊列]纔有排隊資格,且排到最前纔會進入[持有鎖的線程]

以上記好

那麼Monitor.Wait和Monitor.Pulse是什麼意思呢?

Visual Studio中直接按F12或右鍵->轉到定義,我們發現官方解釋是如下

其中Monitor.Pulse的解釋爲:

//摘要:    通知等待隊列中的線程鎖定對象狀態的更改。

//Summary:Notifies a thread in the waiting queue of a change in the locked object's state.

Monitor.Wait中英文釋義如下:

//摘要:    釋放對象上的鎖並阻止當前線程,直到它重新獲取該鎖。如果指定的超時間隔已過,則線程進入就緒隊列。

//Summary:Releases the lock on an object and blocks the current thread until it reacquires the lock.

不知道你們看懂沒,我看上面的摘要的中文看的雲裏霧裏的,英文看的迷迷糊糊的,

按F12或右鍵->轉到定義 相關截圖如下:

Monitor.Pulse解釋如下:

 

然後查好久查到如下微軟官方文檔[2][3]:

 

從微軟官方文檔中總結出

Wait 作用是:將[持有鎖的線程]的本線程狀態改爲[等待隊列]

Pulse作用是:將排在[等待隊列] 最前線程 移到[就緒隊列]

前面我們舉過例子:

1. [持有鎖的線程] 即(結賬中)

2. [就緒隊列]     即(排隊中)

3. [等待隊列]     即(有順序的採購中)

然後

Wait 作用是:將當前結賬的顧客拉回到超市裏面瞎逛,

即當前狀態從(結賬中)轉爲(有順序的採購中)

Pulse作用是:將在超市裏瞎逛的顧客拉去排隊,

即當前狀態從排在最前的(有順序的採購中)狀態轉爲(排隊中)。

微軟官網沒明說,那就說明Pulse後轉到[就緒隊列]的線程很可能會插隊。

那麼又有新的疑問:

<問1>若有多個wait同時起作用,那麼多個線程狀態在[等待隊列]中的排序是?

<問2> 單個Pulse作用是將[等待隊列] 最前線程 移到[就緒隊列]的第幾位?

 

上面兩個問題微軟官網查了好久,沒查到

我們來寫個測試程序測試下:

開6個線程其中[線程A][線程B]中有Wait,[線程C]中有Pulse,通過控制Thread.Sleep來控制線程到達[就緒隊列]的順序爲A, B,C,D,E,F。

部分代碼如下:

private void button7_Click(object sender, EventArgs e)

{

    this.Hide();

    Console.WriteLine("[主線程] " + DateTime.Now.ToString() + "開啓子線程");

    Thread aa = new Thread(A); aa.IsBackground = true; aa.Name = "[線程A]"; aa.Start();

    Thread bb = new Thread(B); bb.IsBackground = true; bb.Name = "[線程B]"; bb.Start();

    Thread cc = new Thread(C); cc.IsBackground = true; cc.Name = "[線程C]"; cc.Start();

    Thread dd = new Thread(D); dd.IsBackground = true; dd.Name = "[線程D]"; dd.Start();

    Thread ee = new Thread(E); ee.IsBackground = true; ee.Name = "[線程E]"; ee.Start();

    Thread ff = new Thread(F); ff.IsBackground = true; ff.Name = "[線程F]"; ff.Start();

    Console.ReadLine();

}

private static object objLockTest = new object();

private static void A()

{

    Console.WriteLine("[線程A] 開啓...");

    Thread.Sleep(100);

    Console.WriteLine("[線程A] [就緒隊列]");

    lock (objLockTest)               //進入[就緒隊列]隊列

    {

        Console.WriteLine("[線程A] [持有鎖的線程]");

        Thread.Sleep(1000);

 

        Console.WriteLine("[線程A] Monitor.Pulse," + DateTime.Now.ToString("HH:mm:ss:fff"));

        //Notifies a thread in the waiting queue of a change in the locked object's state.

        Monitor.Pulse(objLockTest);

        Thread.Sleep(100);

        Console.WriteLine("[線程A] Monitor.Wait ," + DateTime.Now.ToString("HH:mm:ss:fff"));

        //Releases the lock on an object and blocks the current thread until it reacquires the lock.

        //(Monitor.Wait將本線程添加到[等待隊列]

        //超時時間:線程進入就緒隊列之前等待的毫秒數,即從Wait 到Pulse之間的毫秒數,

        //          若無超時時間,且無Pulse喚醒,則本線程一直會處於[等待隊列]

        if (Monitor.Wait(objLockTest, 3000))

            Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        else

            Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(4000);

        Console.WriteLine("[線程A] 退出..." + DateTime.Now.ToString("HH:mm:ss:fff"));

    }  

}

private static void B()

{

    Console.WriteLine("[線程B] 開啓...");

    Thread.Sleep(150);

    Console.WriteLine("[線程B] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程B] [持有鎖的線程]");

        Thread.Sleep(100);

        Console.WriteLine("[線程B] Monitor.Wait," + DateTime.Now.ToString("HH:mm:ss:fff"));

        if (Monitor.Wait(objLockTest, 3000))

            Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        else

            Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程B] 退出...");

    }

}

private static void C()

{

    Console.WriteLine("[線程C] 開啓...");

    Thread.Sleep(200);

    Console.WriteLine("[線程C] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程C] [持有鎖的線程]");

        Thread.Sleep(100);

        Console.WriteLine("[線程C] Monitor.Pulse," + DateTime.Now.ToString("HH:mm:ss:fff"));

        //Notifies a thread in the waiting queue of a change in the locked object's state.

        Monitor.Pulse(objLockTest);

        Thread.Sleep(500);

        Console.WriteLine("[線程C] 退出...");

    }

}

private static void D()

{

    Console.WriteLine("[線程D] 開啓...");

    Thread.Sleep(250);

    Console.WriteLine("[線程D] [就緒隊列]");

    lock (objLockTest) 

    {

        Console.WriteLine("[線程D] [持有鎖的線程]");

        Thread.Sleep(500);

        Console.WriteLine("[線程D] 退出...");

    }

}

private static void E()

{

    Console.WriteLine("[線程E] 開啓...");

    Thread.Sleep(300);

    Console.WriteLine("[線程E] [就緒隊列]");

    lock (objLockTest) 

    {

        Console.WriteLine("[線程E] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程E] 退出...");

    }

}

private static void F()

{

    Console.WriteLine("[線程F] 開啓...");

    Thread.Sleep(350);

    Console.WriteLine("[線程F] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程F] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程F] 退出...");

    }

}

軟件運行結果及對應釋義圖如下:

上圖中綠色畫線處爲Wait ,Pulse使用後的結果的釋義。

我們設置線程到達[就緒隊列]狀態的順序爲:A-> B->C->D->E->F。

[線程A]中有代碼if (Monitor.Wait(objLockTest, 3000))

[線程B]中有代碼if (Monitor.Wait(objLockTest, 3000))

[線程C]中有代碼Monitor.Pulse(objLockTest);

則線程狀態變爲[持有鎖的線程] 順序爲:A(Pulse,Wait)->B(Wait)->C(Pulse)->D->A->E->F

從剛程序中線程[持有鎖的線程] 順序的狀態變化我們得出瞭如下結論:

結論1. 線程中若最先運行的Pulse,則此Pulse無作用。

結論2. 當前運行的線程Wait後會釋放本線程的鎖並將本線程移到[等待隊列]

結論3. 無論當前運行的線程是否調用Pulse,下一個都會運行到原來就排在[就緒隊列]首位的線程。

結論4. 線程Pulse後將[等待隊列] 最前線程 移到[就緒隊列], 即默認將第一個調用Wait的線程移動到[就緒隊列]

結論5. Wait的超時時間統計的是[等待隊列][就緒隊列]所用的時間,即調用Wait的時間與Pulse的時間差,若時間差小於超時時間,則返回True,反之,返回False。

結論6.單個Pulse運行將 [等待隊列] 最前線程 大概率插隊[就緒隊列]的第二位(此結論是從結論3基礎上以邏輯方式推理出來的)

那麼以上兩個問題,我們都有了解釋

<問1>若有多個wait同時起作用,那麼多個線程狀態在[等待隊列]中的排序是?

<答1>多個wait起作用後多個線程依次進入[等待隊列]狀態,即最先進入[等待隊列]的排在最前。

<問2> 單個Pulse作用是將[等待隊列] 最前線程 移到[就緒隊列]的第幾位?

<答2>單個Pulse運行後從本程序上看,應該是[等待隊列] 最前線程 大概率插隊[就緒隊列]的第二位。

 

以上結論與微軟官方文檔釋義相同,

官方文檔截圖如下[4][5]

附贈軟件運行順序及運行後各個線程的狀態圖表:

 

[持有鎖的線程]

[就緒隊列]

[等待隊列]

[主線程] 2020/4/13 13:32:03開啓子線程

 

 

 

[線程C] 開啓...

 

 

 

[線程A] 開啓...

 

 

 

[線程D] 開啓...

 

 

 

[線程E] 開啓...

 

 

 

[線程B] 開啓...

 

 

 

[線程F] 開啓...

 

 

 

[線程A] [就緒隊列]

 

A

 

[線程A] [持有鎖的線程]

A

 

 

[線程B] [就緒隊列]

A

B

 

[線程C] [就緒隊列]

A

B,C

 

[線程D] [就緒隊列]

A

B,C,D

 

[線程E] [就緒隊列]

A

B,C,D,E

 

[線程F] [就緒隊列]

A

B,C,D,E,F

 

[線程A] Monitor.Pulse,13:32:04:161

A

B,C,D,E,F

 

[線程A] Monitor.Wait ,13:32:04:271

 

B,C,D,E,F

A

[線程B] [持有鎖的線程]

B

C,D,E,F

A

[線程B] Monitor.Wait,13:32:04:380

 

C,D,E,F

A,B

[線程C] [持有鎖的線程]

C

D,E,F

A,B

[線程C] Monitor.Pulse,13:32:04:489

C

D,A,E,F

B

[線程C] 退出...

 

D,A,E,F

B

[線程D] [持有鎖的線程]

D

A,E,F

B

[線程D] 退出...

 

A,E,F

B

[線程A] 重新獲得該鎖(在指定的時間過期之前)13:32:05:520

A

E,F

B

軟件的[線程B]中Wait超時時間3000ms
即超時時間爲 13:32:04:380 + 3 = 13:32:07:380

A

E,B,F

 

[線程A] 退出...13:32:09:535

 

E,B,F

 

[線程E] [持有鎖的線程]13:32:09:535

E

B,F

 

[線程E] 退出...

 

B,F

 

[線程B] 重新獲得該鎖(在指定的時間過期之後)13:32:10:051

B

F

 

[線程B] 退出...

 

F

 

[線程F] [持有鎖的線程]13:32:10:566

F

 

 

[線程F] 退出...

 

 

 

 

 

3.Monitor.PulseAll的作用

<問 6>請問Monitor.PulseAll具體的作用是?

多說無益代碼驗證如下

改爲先開啓線程C,即先運行cc.Start();

[線程A]if (Monitor.Wait(objLockTest, 300))

[線程B]if (Monitor.Wait(objLockTest, 3000))

[線程C]if (Monitor.Wait(objLockTest, 3000))

[線程D]Monitor.PulseAll(objLockTest),然後查看軟件運行變化,

改後代碼:

private void button7_Click(object sender, EventArgs e)

{

    this.Hide();

    Console.WriteLine("[主線程] " + DateTime.Now.ToString() + "開啓子線程");

    Thread cc = new Thread(C); cc.IsBackground = true; cc.Name = "[線程C]"; cc.Start();

    Thread aa = new Thread(A); aa.IsBackground = true; aa.Name = "[線程A]"; aa.Start();

    Thread bb = new Thread(B); bb.IsBackground = true; bb.Name = "[線程B]"; bb.Start();

    Thread dd = new Thread(D); dd.IsBackground = true; dd.Name = "[線程D]"; dd.Start();

    Thread ee = new Thread(E); ee.IsBackground = true; ee.Name = "[線程E]"; ee.Start();

    Thread ff = new Thread(F); ff.IsBackground = true; ff.Name = "[線程F]"; ff.Start();

    Console.ReadLine();

}

private static object objLockTest = new object();

private static void A()

{

    Console.WriteLine("[線程A] 開啓...");

    Thread.Sleep(100);

    Console.WriteLine("[線程A] [就緒隊列]");

    lock (objLockTest)               //進入[就緒隊列]隊列

    {

        Console.WriteLine("[線程A] [持有鎖的線程]");

        Thread.Sleep(1000);

 

        Console.WriteLine("[線程A] Monitor.Pulse," + DateTime.Now.ToString("HH:mm:ss:fff"));

        //Notifies a thread in the waiting queue of a change in the locked object's state.

        Monitor.Pulse(objLockTest);

        Thread.Sleep(100);

        Console.WriteLine("[線程A] Monitor.Wait ," + DateTime.Now.ToString("HH:mm:ss:fff"));

        //Releases the lock on an object and blocks the current thread until it reacquires the lock.

        //(Monitor.Wait將本線程添加到[等待隊列]

        //超時時間:線程進入就緒隊列之前等待的毫秒數,即從Wait 到Pulse之間的毫秒數,

        //          若無超時時間,且無Pulse喚醒,則本線程一直會處於[等待隊列]

        if (Monitor.Wait(objLockTest, 300))

            Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        else

            Console.WriteLine("[線程A] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(4000);

        Console.WriteLine("[線程A] 退出..." + DateTime.Now.ToString("HH:mm:ss:fff"));

    }

}

private static void B()

{

    Console.WriteLine("[線程B] 開啓...");

    Thread.Sleep(150);

    Console.WriteLine("[線程B] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程B] [持有鎖的線程]");

        Thread.Sleep(100);

        Console.WriteLine("[線程B] Monitor.Wait," + DateTime.Now.ToString("HH:mm:ss:fff"));

        if (Monitor.Wait(objLockTest, 3000))

            Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        else

            Console.WriteLine("[線程B] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程B] 退出...");

    }

}

private static void C()

{

    Console.WriteLine("[線程C] 開啓...");

    Thread.Sleep(130);

    Console.WriteLine("[線程C] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程C] [持有鎖的線程]");

        Thread.Sleep(100);

        Console.WriteLine("[線程C] Monitor.Wait," + DateTime.Now.ToString("HH:mm:ss:fff"));

        if (Monitor.Wait(objLockTest, 3000))

            Console.WriteLine("[線程C] 重新獲得該鎖(在指定的時間過期之前)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        else

            Console.WriteLine("[線程C] 重新獲得該鎖(在指定的時間過期之後)" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程C] 退出...");

    }

}

private static void D()

{

    Console.WriteLine("[線程D] 開啓...");

    Thread.Sleep(250);

    Console.WriteLine("[線程D] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程D] [持有鎖的線程]");

        Thread.Sleep(100);

        Console.WriteLine("[線程D] Monitor.PulseAll, " + DateTime.Now.ToString("HH:mm:ss:fff"));

        //Notifies a thread in the waiting queue of a change in the locked object's state.

        Monitor.PulseAll(objLockTest);

 

        Thread.Sleep(500);

        Console.WriteLine("[線程D] 退出...");

    }

}

private static void E()

{

    Console.WriteLine("[線程E] 開啓...");

    Thread.Sleep(300);

    Console.WriteLine("[線程E] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程E] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程E] 退出...");

    }

}

private static void F()

{

    Console.WriteLine("[線程F] 開啓...");

    Thread.Sleep(350);

    Console.WriteLine("[線程F] [就緒隊列]");

    lock (objLockTest)

    {

        Console.WriteLine("[線程F] [持有鎖的線程]" + DateTime.Now.ToString("HH:mm:ss:fff"));

        Thread.Sleep(500);

        Console.WriteLine("[線程F] 退出...");

    }

}

軟件運行具體結果及對照如下:

從上面看Monitor.PulseAll爲將[等待隊列]所有的線程移到[就緒隊列],

[就緒隊列]中排序爲:原來排在最前的線程E,然後是以主線程開啓子線程的順序(start的順序)排序。

 

 

 

問:若是一個Monitor.Pulse呢?

答:線程Pulse後將[等待隊列] 最前線程 移到[就緒隊列], 即默認將第一個調用Wait的線程移動到[就緒隊列]

部分代碼及截圖如下:

 

問:若是兩個Monitor.Pulse呢?

答:分別兩次[等待隊列] 最前線程 移到[就緒隊列],

[就緒隊列]中排序爲:原來排在最前的線程E,然後是這兩個子線程開啓的順序(start的順序)排序。

部分代碼及截圖如下:

 

問:若是三個Monitor.Pulse呢?

答:分別三次[等待隊列] 最前線程 移到[就緒隊列],

[就緒隊列]中排序爲:原來排在最前的線程E,然後是這兩個子線程開啓的順序(start的順序)排序。

部分代碼及截圖如下:

 

結論:

只有一個線程,則此線程爲Wait超時線程或[等待隊列]的首線程。

若只有一個Monitor.Pulse,則轉入[就緒隊列]的線程爲第一個Wait的線程。

若  有多個Monitor.Pulse,則轉入[就緒隊列]的線程的順序爲主線程開啓子線程的順序(start的順序)。

 

 

4.總結(Q&A)

 

從上面程序及運行結果得出如下結論:

<問1>若有多個wait同時起作用,那麼多個線程狀態在[等待隊列]中的排序是?

<答1>多個wait起作用後多個線程依次進入[等待隊列]狀態,即最先進入[等待隊列]的排在最前。

<問2> 單個Pulse作用是將[等待隊列] 最前線程 移到[就緒隊列]的第幾位?

<答2>單個Pulse運行後從本程序上看,應該是[等待隊列] 最前線程 大概率插隊[就緒隊列]的第二位(如上軟件運行結果及對應釋義圖)

 

個人增加問題及答案:

<問 3>wait的超時時間及返回值的作用是?

<答 3>超時時間爲當前線程從[等待隊列]到進入[就緒隊列]的時間差,

超時時間作用如下:

a.超時時間爲0,則本線程直接進入[就緒隊列]

b.若已超時,則本線程會自動進入[就緒隊列]。

返回值的作用如下:

a.本線程重新獲取該鎖後,若在指定的時間過期之前從[等待隊列]進入[就緒隊列],返回值爲True,

b.本線程重新獲取該鎖後,若在指定的時間過期之後從[等待隊列]進入[就緒隊列],返回值爲False。

 

<問 4>線程如何從[等待隊列]進入[就緒隊列] ?

<答 4>兩種方式

a.第一種wait設定超時時間,超時後自動進入[就緒隊列] (如上軟件運行結果及對應釋義圖)

b.第二種其他線程運行Monitor.Pulse(同參數), [等待隊列]最前線程移動到[就緒隊列]

 

<問 5>正常情況下Wait與Pulse的調用順序是?分別什麼影響?

<答 5>理論上應該是 某個線程先調用Monitor.Wait,然後另一線程再調用Monitor.Pulse,具體使用方法參考上面的代碼。

[等待隊列]中無線程,另一線程先調用Monitor.Pulse,某個線程再調用Monitor.Wait,則Monitor.Pulse無作用(如上軟件運行結果及對應釋義圖中線程A),

且後面調用的Monitor.Wait可能會導致死鎖(參考鏈接微軟官方文檔[4])。爲防止死鎖,則建議在調用Monitor.Wait時設置足夠的超時時間。

 

<問 6>請問Monitor.PulseAll具體的作用是?

<答 6>作用爲將[等待隊列]的所有線程移到[就緒隊列]中,並放到[就緒隊列]的第二位。

若有多個線程,則以主線程開啓子線程的順序(start的順序)排序。

 

[等待隊列]中的排隊順序爲:調用Wait的順序依次排列

[就緒隊列]中的排隊順序爲:隊伍首線程,然後是“Wait超時,或調用後Pulse/PulseAll的線程”,再是其他線程。

若“Wait超時,或調用後Pulse/PulseAll的線程”

只有一個線程,則此線程爲Wait超時線程或[等待隊列]的首線程。

若有多個線程則排列順序爲:主線程開啓子線程的順序(start的順序)。

 

關於Wait和Pulse的問與答:

<問>線程Wait後如何回到[持有鎖的線程] ?

<答>當前線程運行到wait後進入了[等待隊列],而本線程若想重新進入[持有鎖的線程]則必須先轉爲[就緒隊列]狀態並排堆,只有進入[就緒隊列]且排隊後纔有可能轉爲[持有鎖的線程]。

<問>若wait需要設超時時間嗎?

<答>我們都知道線程運行到wait後則進行到[等待隊列],需要通過Monitor.Pulse(同參數)或超時時間進入[就緒隊列],否則本線程就會一直處於[等待隊列]

<問>Monitor.Pulse會將線程移到[就緒隊列]的哪裏?

<答> 個人認爲會直接移動到[就緒隊列]的第二位,即當前狀態爲(排隊中)的第二個

Monitor.Pulse後會將同參數中處於[等待隊列] 最前的線程移動[就緒隊列]

而Monitor.PulseAll會將同參數中處於[等待隊列] 所有線程移到[就緒隊列]

 

 

 

 

 

編譯環境:Visual Studio 2012

編輯框架:.NET Framework 4.0

編程語言:C#

源代碼鏈接:https://download.csdn.net/download/shengmingzaiyuxuexi/12327588

 

參考鏈接

[1]:https://docs.microsoft.com/zh-cn/dotnet/standard/threading/managed-threading-best-practices

[2]:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor?view=netframework-4.8

[3]:https://docs.microsoft.com/en-us/dotnet/api/system.threading.monitor?view=netframework-4.8

[4]:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor.pulse?view=netframework-4.8

[5]:https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.monitor.wait?view=netframework-4.8

有錯誤,請指正,有疑問,請留言,與君共勉,共同進步!

謝老闆的觀,看您的肯定就是我創作的最大動力,下期見!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章