前言ide
衆所周知,Thread類中的掛起線程和恢復線程微軟已標記過期,由於可能會形成問題函數
Resume() 恢復當前線程 |
已過期。 Resumes a thread that has been suspended.ui |
Suspend() 掛起當前線程 |
已過期。 掛起線程,或者若是線程已掛起,則不起做用。spa |
其餘方式實現線程
1、ThreadWorkItemcode
class ThreadWorkItem { public int ThreadManagerId { get; set; } public Thread Thread { get; set; } public string ThreadName { get; set; } public bool Flag { get; set; } public ManualResetEvent ManualResetEvent { get; set; } }
2、C# Thread掛起線程和恢復線程的實現的兩種方式blog
方式1:使用變量開關控制掛起線程和恢復線程,具體代碼以下get
public class Program { //線程工做集合 private static List<ThreadWorkItem> Works = new List<ThreadWorkItem>(); //方式1:使用變量開關控制掛起線程和恢復線程 private static void Main(string[] args) { ThreadWorkItem wItem = null; Thread t = null; var threadNum = 2; for (int i = 0; i < threadNum; i++) { t = new Thread(o=> { var w = o as ThreadWorkItem; if (w == null) return; while (true) { if (!w.Flag) { Console.WriteLine("我是線程:" + Thread.CurrentThread.Name); Thread.Sleep(1000); continue; } //避免CPU空轉 Thread.Sleep(5000); } }); //$ C#6.0語法糖 t.Name = $"Hello I'am 線程:{i}-{t.ManagedThreadId}"; wItem = new ThreadWorkItem { Flag = false, Thread = t, ThreadManagerId = t.ManagedThreadId, ThreadName = t.Name }; Works.Add(wItem); t.Start(Works[i]); } //5秒後容許一個等待的線程繼續。當前容許的是線程1 Thread.Sleep(5000); Works[0].Flag = true; Console.WriteLine($"thread-{Works[0].ThreadName} is 暫停"); //5秒後容許一個等待的線程繼續。當前容許的是線程0,1 Thread.Sleep(5000); Works[0].Flag = false; Console.WriteLine($"thread-{Works[0].ThreadName} is 恢復"); } }
方式2:使用ManualResetEvent控制掛起線程和恢復線程(推薦);替代Thread類中被微軟標記過期的函數(內核模式非混合模式)string
public class Program { //線程工做集合 static List<ThreadWorkItem> Works = new List<ThreadWorkItem>(); //方式2:使用ManualResetEvent控制掛起線程和恢復線程(推薦);替代Thread類中被微軟標記過期的函數 static void Main(string[] args) { Task.Factory.StartNew(() => { Thread t = null; ThreadWorkItem item = null; for (int i = 0; i < 2; i++) { t = new Thread((o) => { var w = o as ThreadWorkItem; if (w == null) return; while (true) { //阻塞當前線程 w.ManualResetEvent.WaitOne(); Console.WriteLine("我是線程:" + Thread.CurrentThread.Name); Thread.Sleep(1000); } }); t.Name = "Hello,i 'am Thread: " + i; item = new ThreadWorkItem { //線程0,1持續運行,設置true後非阻塞,持續運行。須要手動觸發Reset()纔會阻塞實例所在當前線程 ManualResetEvent = new ManualResetEvent(true), Thread = t, ThreadManagerId = t.ManagedThreadId, ThreadName = t.Name }; Works.Add(item); t.Start(item); } //5秒後準備暫停一個線程1。線程0持續運行 Thread.Sleep(5000); Console.WriteLine("close..."); Works[1].ManualResetEvent.Reset(); //5秒後恢復線程1;線程0,1持續運行 Thread.Sleep(5000); Console.WriteLine("open..."); Works[1].ManualResetEvent.Set(); //5秒後準備暫停一個線程0。線程1持續運行 Thread.Sleep(5000); Console.WriteLine("close0..."); Works[0].ManualResetEvent.Reset(); //5秒後恢復線程1;線程0,1持續運行 Thread.Sleep(5000); Console.WriteLine("open0..."); Works[0].ManualResetEvent.Set(); }); Console.ReadLine(); } }
3、總結it
1.有時候會以爲必須由主線程建立ManualResetEvent實例才能起到做用,實際並非這樣的,上述方式2則證實了這一點。
2.那麼AutoResetEvent作不到一樣的效果嗎?
答:AutoResetEvent 顧名思義,自動Reset()表示重置信號量狀態,當前線程中持有WaitOne()就又會被持續阻塞。而ManualResetEvent必需要手動調用Reset()才能重置信號量,這裏再解釋下Set(),它代表容許一個或多個被同一個ManualResetEvent實例WaitOne()的線程放行。
3.實例化信號量的構造參數是什麼意思?
答:信號量非終止狀態,若是值爲false則代表終止狀態,調用WaitOne()方法的時候當即阻塞。設置true能夠理解爲隱式調用了Set()方法放行一次。
4. ManualResetEvent和AutoResetEvent的區別
答:ManualResetEvent調用Set()容許一個或多個被同一個ManualResetEvent實例WaitOne()的線程放行。
AutoResetEvent調用Set() 只能容許一個線程放行。若是多處使用同一個實例,則須要手動調用屢次Set()