锁之锁的三种状态及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

有错误,请指正,有疑问,请留言,与君共勉,共同进步!

谢老板的观,看您的肯定就是我创作的最大动力,下期见!

 

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