image

Worker類別

public class Worker
{
/* Initializes a new intance of the ManualRestEvent class
* with a Boolean value indicating whether to set the
* initial state signaled
*/
private ManualResetEvent m_pauseEvent = new ManualResetEvent(true);
private ManualResetEvent m_shutdownEvent = new ManualResetEvent(false);
private Thread m_thread;
private int m_cnt = 0;
private string m_status;
private Label m_lbl;
private TextBox m_tBox;
private ProgressBar m_pBar;


public int UserID { get; set; }
public string Status
{
get { return m_status; }
}
public int Count
{
get { return m_cnt; }
set { m_cnt = value; }
}
public Worker() { }
public Worker(Label lbl, TextBox tBox, ProgressBar pBar)
{
m_lbl = lbl;
m_tBox = tBox;
m_pBar = pBar;
}
#region Job
public void Job()
{
const int UPDATE_PERIOD = 10000;
while (true)
{
/* 若收到訊號, 則m_pauseEvent程式繼續往下執行
* 反之, 沒有收到訊號, 則持續等待(infinite),
* 程式不會往下執行(凍結)
*/
m_pauseEvent.WaitOne(Timeout.Infinite);
/* 若沒有收到訊號, 則一直等待訊號,
* 但因為timeout設定等待 0 ms, 自動跳開回傳false
* 反之, 收到訊號, 回傳true
*/
if(m_shutdownEvent.WaitOne(0))
break;
m_cnt++;
if (m_cnt % UPDATE_PERIOD == 0)
{
updateTextBox();
updateProgressBar();
}

}
}
#endregion
#region Start
public void Start()
{
m_thread = new Thread(Job);
m_thread.Start();
m_status = "執行緒開始執行...";
updateLabel();
}
#endregion
#region Pause
public void Pause()
{
// 將事件設定為未收到訊號, 會造成執行緒封鎖
m_pauseEvent.Reset();
m_status = "執行緒暫停";
updateLabel();
}
#endregion
#region Resume
public void Resume()
{
// 將事件設定為收到訊號, 會封鎖的執行緒繼續
m_pauseEvent.Set();
m_status = "執行緒繼續";
updateLabel();
}
#endregion
#region Stop
public void Stop()
{
/* m_shutdownEven事件收到訊號,
* 則(m_shutdownEvent.WaitOne(0))
* 回傳true
*/
m_shutdownEvent.Set();
/* 記得通知_pauseEvent, 即_pauseEvent.Set();
* 否則通知_shutdownEvent也枉然
*/
m_pauseEvent.Set();
/* 優雅地等執行緒結束,
* 即 呼叫_thread.Join();
* 而不是Thread.Terminate
*/
m_thread.Join();
m_status = "執行緒停止";
updateLabel();
}
#endregion
#region Reset Cnt
public void ResetCnt()
{
m_cnt = 0;
}
#endregion
#region Update UI
public void updateLabel()
{
if (m_lbl.InvokeRequired)
{
m_lbl.BeginInvoke((Action)(() => { updateLabel(); }));
}
else
{
m_lbl.Text = m_status;
}
}
public void updateTextBox()
{
if (m_tBox.InvokeRequired)
{
m_tBox.BeginInvoke((Action)(() => { updateTextBox(); }));
}
else
{
m_tBox.Text = m_cnt.ToString();
}
}
public void updateProgressBar()
{
if (m_pBar.InvokeRequired)
{
m_pBar.BeginInvoke((Action) (()=>{ updateProgressBar();}) );
}
else
{
m_pBar.Value = m_cnt;
}
}
#endregion
}

測試Worker類別

public partial class Form1 : Form
{
Worker worker1, worker2;
//public delegate void UpdateTextBox();
//public delegate void UpdateProgressBar();
public Form1()
{
InitializeComponent();


}

private void startToolStripMenuItem_Click(object sender, EventArgs e)
{
worker1 = new Worker(label1, textBox1, progressBar1);
worker1.Start();
startToolStripMenuItem.Enabled = false;
pauseToolStripMenuItem.Enabled = true;
stopToolStripMenuItem.Enabled = true;
resetCntToolStripMenuItem.Enabled = true;
}

private void startToolStripMenuItem1_Click(object sender, EventArgs e)
{
worker2 = new Worker(label2, textBox2, progressBar2);
worker2.Start();
startToolStripMenuItem1.Enabled = false;
pauseToolStripMenuItem1.Enabled = true;
stopToolStripMenuItem1.Enabled = true;
resetCntToolStripMenuItem1.Enabled = true;
}

private void pauseToolStripMenuItem_Click(object sender, EventArgs e)
{
worker1.Pause();
pauseToolStripMenuItem.Enabled = false;
resumeToolStripMenuItem.Enabled = true;
}

private void pauseToolStripMenuItem1_Click(object sender, EventArgs e)
{
worker2.Pause();
pauseToolStripMenuItem1.Enabled = false;
resumeToolStripMenuItem1.Enabled = true;
}

private void resumeToolStripMenuItem_Click(object sender, EventArgs e)
{
worker1.Resume();
resumeToolStripMenuItem.Enabled = false;
pauseToolStripMenuItem.Enabled = true;
stopToolStripMenuItem.Enabled = true;
}

private void resumeToolStripMenuItem1_Click(object sender, EventArgs e)
{
worker2.Resume();
resumeToolStripMenuItem1.Enabled = false;
pauseToolStripMenuItem1.Enabled = true;
stopToolStripMenuItem1.Enabled = true;
}

private void stopToolStripMenuItem_Click(object sender, EventArgs e)
{
worker1.Stop();
stopToolStripMenuItem.Enabled = false;
startToolStripMenuItem.Enabled = true;
pauseToolStripMenuItem.Enabled = false;
resetCntToolStripMenuItem.Enabled = false;

}

private void stopToolStripMenuItem1_Click(object sender, EventArgs e)
{
worker2.Stop();
stopToolStripMenuItem1.Enabled = false;
startToolStripMenuItem1.Enabled = true;
pauseToolStripMenuItem1.Enabled = false;
resetCntToolStripMenuItem1.Enabled = false;
}

private void resetCntToolStripMenuItem_Click(object sender, EventArgs e)
{
worker1.ResetCnt();
}

private void resetCntToolStripMenuItem1_Click(object sender, EventArgs e)
{
worker2.ResetCnt();
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (worker1 != null) worker1.Stop();
if (worker2 != null) worker2.Stop();
}
}

測試影片: https://youtu.be/RsMKi9Em0do 

====================================================================

Question: 若主執行緒暫停, 是否會影響Worker1和Worker2執行緒的運行?

更動:

1. 讓Job每隔1秒, m_cnt增加1

2. UPDATE_PERIOD = 1

public void Job()
{
const int UPDATE_PERIOD = 1;
while (true)
{
/* 若收到訊號, 則m_pauseEvent程式繼續往下執行
* 反之, 沒有收到訊號, 則持續等待(infinite),
* 程式不會往下執行(凍結)
*/
m_pauseEvent.WaitOne(Timeout.Infinite);
/* 若沒有收到訊號, 則一直等待訊號,
* 但因為timeout設定等待 0 ms, 自動跳開回傳false
* 反之, 收到訊號, 回傳true
*/
if(m_shutdownEvent.WaitOne(0))
break;
m_cnt++;
if (m_cnt % UPDATE_PERIOD == 0)
{
updateTextBox();
updateProgressBar();
}
Thread.Sleep(1000);
}
}

image

UI Thread

private void sleepToolStripMenuItem_Click(object sender, EventArgs e)
{
Thread.Sleep(5000);
}

Answer: 

暫停期間UI不更新資訊, Worker1和Worker2執行緒照常計數

所以不影響Worker1和Worker2執行緒的運行

測試影片: https://youtu.be/28ZZA7_isew


範例程式: ThreadUpdateUI

參考資料:

arrow
arrow
    全站熱搜

    me1237guy 發表在 痞客邦 留言(0) 人氣()