詳解C# 線程的掛起與喚醒
如果說C#和C++有什么不同,博主不得不說,對于異步的支持程度是C#的一一個偉大的進步。
其實早期的C++都沒有異步,并發(fā)的概念。博主第一次使用C++創(chuàng)建異步程序的時候,是使用boost庫的內容進行實現(xiàn)的。相對而言,C#對于異步的支持可以說是相當?shù)暮?。相信很多名詞大家都很耳熟能詳,比如說Thread,BeginInvoke,Delegate,backgroundworker等等。。。其實樓主在使用了這么多的異步操作過程中,還是覺得backgroudworker比較好用。
當然,我們今天要說的和上面的無關。講述的是如何在線程中進行掛起喚醒操作。
假設,有一個Thread現(xiàn)在需要掛起,等到合適的時候再喚醒那么這個線程(消費者模式)。如果大家需要用Suspend,Resume操作,我建議還是要思考再三。以下是msdn原話(https://msdn.microsoft.com/zh-cn/library/system.threading.thread.suspend(v=vs.110).aspx):
Do not use the Suspend and Resume methods to synchronize the activities of threads. You have no way of knowing what code a thread is executing when you suspend it. If you suspend a thread while it holds locks during a security permission evaluation, other threads in the AppDomain might be blocked. If you suspend a thread while it is executing a class constructor, other threads in the AppDomain that attempt to use that class are blocked. Deadlocks can occur very easily.
本篇文章要說的線程掛起與繼續(xù)的方式其實是利用AutoResetEvent和ManualResetEvent的方法進行堵塞和繼續(xù)的。
在介紹AutoResetEvent和ManualResetEvent之前,先介紹一個概念,就是線程中Set()和Reset()的區(qū)別。
- set:指的是將一個事件設置為有信號,那么被這個事件堵塞的線程就會繼續(xù)下去。
- reset:指的是將一個事件設置為無信號,那么嘗試繼續(xù)的事件就會被堵塞。
一,AutoResetEvent類
這個類的字面意思就能夠解釋一切:自動reset的事件,就是這個事件一旦set之后,如果某個線程堵塞被繼續(xù)了,那么就會自動reset。下一次如果嘗試繼續(xù),依然會被堵塞。
其中AutoResetEvent類的構造函數(shù)有一個參數(shù) 是bool型。
MSDN的解釋是:
Initializes a new instance of the AutoResetEvent class with a Boolean value indicating whether to set the initial state to signaled.
如果這個參數(shù)是true,那么第一次嘗試繼續(xù)就不會被阻塞。如果這個參數(shù)是false,那么第一次嘗試繼續(xù)就會被堵塞。
以下是測試代碼,取自MSDN:
using System;
using System.Threading;
// Visual Studio: Replace the default class in a Console project with
// the following class.
class Example
{
private static AutoResetEvent event_1 = new AutoResetEvent(true);
private static AutoResetEvent event_2 = new AutoResetEvent(false);
static void Main()
{
Console.WriteLine("Press Enter to create three threads and start them.\r\n" +
"The threads wait on AutoResetEvent #1, which was created\r\n" +
"in the signaled state, so the first thread is released.\r\n" +
"This puts AutoResetEvent #1 into the unsignaled state.");
Console.ReadLine();
for (int i = 1; i < 4; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(250);
for (int i = 0; i < 2; i++)
{
Console.WriteLine("Press Enter to release another thread.");
Console.ReadLine();
event_1.Set();
Thread.Sleep(250);
}
Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
for (int i = 0; i < 3; i++)
{
Console.WriteLine("Press Enter to release a thread.");
Console.ReadLine();
event_2.Set();
Thread.Sleep(250);
}
// Visual Studio: Uncomment the following line.
//Console.Readline();
}
static void ThreadProc()
{
string name = Thread.CurrentThread.Name;
Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
event_1.WaitOne();
Console.WriteLine("{0} is released from AutoResetEvent #1.", name);
Console.WriteLine("{0} waits on AutoResetEvent #2.", name);
event_2.WaitOne();
Console.WriteLine("{0} is released from AutoResetEvent #2.", name);
Console.WriteLine("{0} ends.", name);
}
}
其中,AutoResetEvent.WaitOne()這個方法就是線程中嘗試繼續(xù)。如果沒有SET信號,那么就會一直阻塞,如果收到Set信號該線程就會繼續(xù)。但是因為是AutoResetEvent,所以下一次waitOne依然會被阻塞。
上面代碼的輸出結果是:
Press Enter to create three threads and start them. The threads wait on AutoResetEvent #1, which was created in the signaled state, so the first thread is released. This puts AutoResetEvent #1 into the unsignaled state. Thread_1 waits on AutoResetEvent #1. Thread_1 is released from AutoResetEvent #1. Thread_1 waits on AutoResetEvent #2. Thread_3 waits on AutoResetEvent #1. Thread_2 waits on AutoResetEvent #1. Press Enter to release another thread. Thread_3 is released from AutoResetEvent #1. Thread_3 waits on AutoResetEvent #2. Press Enter to release another thread. Thread_2 is released from AutoResetEvent #1. Thread_2 waits on AutoResetEvent #2. All threads are now waiting on AutoResetEvent #2. Press Enter to release a thread. Thread_2 is released from AutoResetEvent #2. Thread_2 ends. Press Enter to release a thread. Thread_1 is released from AutoResetEvent #2. Thread_1 ends. Press Enter to release a thread. Thread_3 is released from AutoResetEvent #2. Thread_3 ends.
二,ManualResetEvent
ManualResetEvent和AutoResetEvent大部分概念都是相同的,最大的不同就是一個是自動reset一個是手動reset。也就是說,如果使用ManualResetEvent類,一旦Set之后,所有已經阻塞的線程(waitone())都會繼續(xù)。而且之后調用waitone的線程也不會被堵塞,除非手動再次Reset。也就是說,這個類是手動開啟關閉信號的事件。
以下是測試代碼,取自MSDN:
using System;
using System.Threading;
public class Example
{
// mre is used to block and release threads manually. It is
// created in the unsignaled state.
private static ManualResetEvent mre = new ManualResetEvent(false);
static void Main()
{
Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n");
for(int i = 0; i <= 2; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(500);
Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" +
"\nto release all the threads.\n");
Console.ReadLine();
mre.Set();
Thread.Sleep(500);
Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" +
"\ndo not block. Press Enter to show this.\n");
Console.ReadLine();
for(int i = 3; i <= 4; i++)
{
Thread t = new Thread(ThreadProc);
t.Name = "Thread_" + i;
t.Start();
}
Thread.Sleep(500);
Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" +
"\nwhen they call WaitOne().\n");
Console.ReadLine();
mre.Reset();
// Start a thread that waits on the ManualResetEvent.
Thread t5 = new Thread(ThreadProc);
t5.Name = "Thread_5";
t5.Start();
Thread.Sleep(500);
Console.WriteLine("\nPress Enter to call Set() and conclude the demo.");
Console.ReadLine();
mre.Set();
// If you run this example in Visual Studio, uncomment the following line:
//Console.ReadLine();
}
private static void ThreadProc()
{
string name = Thread.CurrentThread.Name;
Console.WriteLine(name + " starts and calls mre.WaitOne()");
mre.WaitOne();
Console.WriteLine(name + " ends.");
}
}
輸出結果是:
Start 3 named threads that block on a ManualResetEvent: Thread_0 starts and calls mre.WaitOne() Thread_1 starts and calls mre.WaitOne() Thread_2 starts and calls mre.WaitOne() When all three threads have started, press Enter to call Set() to release all the threads. Thread_2 ends. Thread_0 ends. Thread_1 ends. When a ManualResetEvent is signaled, threads that call WaitOne() do not block. Press Enter to show this. Thread_3 starts and calls mre.WaitOne() Thread_3 ends. Thread_4 starts and calls mre.WaitOne() Thread_4 ends. Press Enter to call Reset(), so that threads once again block when they call WaitOne(). Thread_5 starts and calls mre.WaitOne() Press Enter to call Set() and conclude the demo. Thread_5 ends.
ManualResetEvent類的輸出結果與AutoResetEvent輸出結果最大的不同是在于:
如果不手動Reset,一旦調用Set方法,那么ManualResetEvent.WaitOne()就不會堵塞。
但是,AutoResetEvent會自動Reset,所以哪怕不手動Reset,每一次AutoResetEvent.WaitOne()都需要Set方法進行觸發(fā)以繼續(xù)線程。
以上就是詳解C# 線程的掛起與喚醒的詳細內容,更多關于C# 線程的掛起與喚醒的資料請關注腳本之家其它相關文章!
相關文章
Jquery+Ajax+Json+存儲過程實現(xiàn)高效分頁
這篇文章主要介紹Jquery+Ajax+Json+存儲過程實現(xiàn)分頁,需要的朋友可以參考下2015-08-08
C# Winform調用百度接口實現(xiàn)人臉識別教程(附源碼)
這篇文章主要介紹了C# Winform調用百度接口實現(xiàn)人臉識別教程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-05-05
C# CAD SelectionFilter下TypedValue數(shù)組使用方式
這篇文章主要介紹了C# CAD SelectionFilter下TypedValue數(shù)組使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02

