[C#][Thread] 控制執行緒 開始/暫停/恢復/停止 的方法
前言:
最近BOSS叫我試著開發Android版本的溫溼度監控系統,他打算年底可以上線去賣
外加我身上還有一些CASE要做,所以一陣子沒上來寫筆記
不過我還是個小菜鳥... Andorid對我來說還有點吃力
可能之後會新增一些Xamarin的技巧文章吧,目前還在研究(汗)
今天抽空來整理一下我覺得還不錯用的執行緒操作用法
平常我們使用執行緒的時候並不會特別想要管控正在Run的執行緒
通常是等執行緒做完他該做的即會自動釋放資源
但如果像我做的監控軟體這樣,要不斷的向測點撈取數值的話
那麼管理執行緒,不讓他因使用者的操作而暴走拖垮效能就顯得特別重要
以下是我常用的操作法,如果有更好的做法也請跟我說,感謝
首先,先新增一個ThreadWork類別
話不多說,先貼上程式碼後再解釋
public class ThreadWorker
{
Thread _thread;
ManualResetEvent _shutdownEvent;
ManualResetEvent _pauseEvent;
public void ThreadJob()
{
while (true)
{
// pause event : if WaitHandle is false, it will wait and return false
_pauseEvent.WaitOne(Timeout.Infinite);
// stop event
if (_shutdownEvent.WaitOne(0)) break;
// work here
Console.WriteLine(DateTime.Now);
// like Thread.Sleep(1000), but higher efficiency
SpinWait.SpinUntil(() => false, 1000);
}
Console.WriteLine("Work is completed or stopped");
}
public void Start()
{
Console.WriteLine("Add a new thread");
_thread = new Thread(ThreadJob);
_shutdownEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
_thread.IsBackground = true;
_thread.Start();
}
public void Pause()
{
// Set WaitHandle false
_pauseEvent.Reset();
}
public void Resume()
{
// Set WaitHandle true
_pauseEvent.Set();
}
public void Stop()
{
// trigger stop
_shutdownEvent.Set();
// if thread suspend, let it resume.
_pauseEvent.Set();
_thread.Join();
_thread = null;
}
}
簡單的來說,就是在一個無窮迴圈中加入【工作事項】跟【暫停(等待)】和【停止(跳出)】事件
ManualResetEvent _ManualResetEvent = new ManualResetEvent(bool);
參數 bool值 可視為設定ManualResetEvent類別中的WaitOne()方法是否該執行等待(true為收到通知,不會進入WaitOne等待)
所以_pauseEvent一開始必須是true;而_shutdownEvent則是false且WaitOne內為0
而WaitOne()本身會回傳一boolean值表示WaitHandle的通知狀態
故停止事件可以寫作
if (_shutdownEvent.WaitOne(0)) break;
另外我在此的工作內容為印出現在時間
並用SpinWait.SpinUntil(() => false, 1000); 讓執行緒休息一秒
如果想簡略,也可把這一秒加在停止事件中,變成
if (_shutdownEvent.WaitOne(1000)) break;
只是這樣以後可能會發生不知道自己在寫甚麼(汗)
接著就是用Console來測試看看囉!
class Program
{
static void Main(string[] args)
{
ThreadWorker _threadWorker = new ThreadWorker();
Console.WriteLine("[Start 5s]");
_threadWorker.Start();
Thread.Sleep(5000);
Console.WriteLine("[Pause 10s]");
_threadWorker.Pause();
Thread.Sleep(10000);
Console.WriteLine("[Resume 3s]");
_threadWorker.Resume();
Thread.Sleep(3000);
Console.WriteLine("[Stop]");
_threadWorker.Stop();
Thread.Sleep(5000);
Console.WriteLine("[Start again 3s]");
_threadWorker.Start();
Thread.Sleep(3000);
Console.WriteLine("[Pause 3s]");
_threadWorker.Pause();
Thread.Sleep(3000);
Console.WriteLine("[Resume 2s]");
_threadWorker.Resume();
Thread.Sleep(2000);
Console.WriteLine("[Stop]");
_threadWorker.Stop();
Console.ReadKey();
}
}
印出的結果為
你可能會想問執行5秒怎會印出6個秒數
原因是你呼叫暫停或停止後
當下迴圈還是必須要跑完才會看到停止/暫停
所以會多做一次工才結束/停止
新手發文,有謬誤請告知,也請多多指教。