แต่ก็มีหลายกรณีที่จำเป็นต้องบังคับให้ Thread ทำงานตามๆกันไปโดยไม่พร้อมกัน การทำให้ Thread ทำงานจนจบก่อนที่จะไปทำที่ Thread อื่น
ผู้เขียนจะทำตัวอย่างโปรแกรมโดยใช้ คำสั่ง lock(Instance){} เพื่อเป็นการทำให้การทำงาน Thread ทำงานเสร็จก่อน โดยจะมี Control ProgressBar 4 ตัว ที่จะทำงานตามลำดับกันไป GUI ตามภาพด้านล่าง
ผู้เขียนจะไม่ทำงานตั้งค่าเริ่มต้นของแต่ละ Control .ในขั้นตอน Design ที่จะทำการตั้งค่าทั้งหมดตอน Runtime โดยที่
- ฟอร์ม ตั้งชื่อ threadSEQ
- ปุ่ม Start ตั้งชื่อ StartBtn
- ProgressBar ทั้ง 4 ให้มีชื่อเป็น Default
ผู้เขียนสร้าง Type ขึ้นมา 2 กลุ่มคือ
enum setprogress { spReset,spStart}
enum setThread{stCreate,stAbort}
Member ของ Class มีอยู่ตัวเดียวคือ
private Thread[] t;
t เป็น Member ที่เป็น array ของ Thread ทั้งหมด
method ที่เป็นการกำหนดค่าต่างๆ และทำให้ Thread ต่างๆ ถูกสร้างขึ้นคือ
//method setAllProgress มี parameter เป็น Type setprogress ที่สร้างขึ้นตอนแรก และมี Pass by referance นับค่า Thread ที่เกิดขึ้น
private void setAllProgress(setprogress value,ref int ThreadPGCount)
{
//ให้เริ่มต้นนับ Thread เป็น 0
ThreadPGCount = 0;
//สร้าง Object Random เพื่อใช้ในการสุ่มค่าสูงสุดของ ProgressBar
Random rd = new Random();
//วนลูป Control ทั้งหมดที่อยู่บนฟอร์ม
foreach (Control c in this.Controls)
{
//ถ้า Control ที่พบใช่ชนิด ProgressBar
if (c is ProgressBar)
{
ProgressBar p = (ProgressBar)c;
//ตรวจสอบคำสั่งที่ให้ทำงาน
if (value == setprogress.spReset)
{
p.Minimum = 0;
p.Maximum = rd.Next(100,500);
p.Step = 1;
p.Value = 0;
}
else if (value == setprogress.spStart)
{
this.t[ThreadPGCount].Start(p);
}
//นับจำนวน Thread ที่จะใช้ทำงาน
ThreadPGCount++;
}
}
}
method runprogress การทำงานของ Thread
private void runprogress(object o)
{
//แปลงค่า Control ProgressBar ที่ส่งเข้ามา
ProgressBar pg = (ProgressBar)o;
lock (this)
{
while (pg.Value < pg.Maximum)
{
pg.PerformStep();
Thread.Sleep(10);
this.Text = "Runing " + pg.Value + "(" + pg.Maximum + ")";
this.Update();
}
}
}
private void setAllThread(setThread value)
{
//วนลูป Thread ทั้งหมด
for (int i = 0; i < this.t.Length; i++)
{
if (value == setThread.stCreate) //ให้สร้าง Thread
this.t[i] = new Thread(this.runprogress);
else if (value == setThread.stAbort) //ให้จบการทำงานของ Thread
this.t[i].Abort();
}
}
method ต่างๆนำไปใช้งานภายใน Constructor เพื่อให้กำหนดค่าทั้งหมด
public threadSEQ()
{
InitializeComponent();
threadSEQ.CheckForIllegalCrossThreadCalls = false;
int tid = 0; //เก็บจำนวน Thread ที่ต้องใช้
this.setAllProgress(setprogress.spReset,ref tid);
this.t = new Thread[tid]; //สร้าง Thread array ตามจำนวน Thread ที่ต้องใช้
this.setAllThread(setThread.stCreate);
}
ปุ่ม Start เรียกใช้ method ที่ได้สร้างขึ้นมาแล้ว
private void StartBtn_Click(object sender, EventArgs e)
{
int i=0;
this.setAllProgress(setprogress.spStart,ref i);
}
ที่จะลืมไม่ได้ก็คือตอนมีการปิดฟอร์ม ก็ต้องให้ Thread หยุดทำงานทั้งหมด เพื่อป้องกันการทำงานของ Thread ที่อาจจะค้างอยู่ได้
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
this.setAllThread(setThread.stAbort);
}
ภาพรวมของ Class ทั้งหมด
ทดสอบการทำงานของโปรแกรมเมื่อกดปุ่ม Start
ProgressBar แต่ละตัวก็จะทำงานโดยรอทำงานตามกันไป ไม่ทำงานพร้อมกัน
Code ทั้งหมดของฟอร์ม threadSEQ
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace testThread
{
public partial class threadSEQ : Form
{
enum setprogress { spReset,spStart}
enum setThread{stCreate,stAbort}
private Thread[] t;
public threadSEQ()
{
InitializeComponent();
threadSEQ.CheckForIllegalCrossThreadCalls = false;
int tid = 0;
this.setAllProgress(setprogress.spReset,ref tid);
this.t = new Thread[tid];
this.setAllThread(setThread.stCreate);
}
private void setAllProgress(setprogress value,ref int ThreadPGCount)
{
ThreadPGCount = 0;
Random rd = new Random();
foreach (Control c in this.Controls)
{
if (c is ProgressBar)
{
ProgressBar p = (ProgressBar)c;
if (value == setprogress.spReset)
{
p.Minimum = 0;
p.Maximum = rd.Next(100,500);
p.Step = 1;
p.Value = 0;
}
else if (value == setprogress.spStart)
{
this.t[ThreadPGCount].Start(p);
}
ThreadPGCount++;
}
}
}
private void setAllThread(setThread value)
{
for (int i = 0; i < this.t.Length; i++)
{
if (value == setThread.stCreate)
this.t[i] = new Thread(this.runprogress);
else if (value == setThread.stAbort)
this.t[i].Abort();
}
}
private void runprogress(object o)
{
ProgressBar pg = (ProgressBar)o;
lock (this)
{
while (pg.Value < pg.Maximum)
{
pg.PerformStep();
Thread.Sleep(10);
this.Text = "Runing " + pg.Value + "(" + pg.Maximum + ")";
this.Update();
}
}
}
private void StartBtn_Click(object sender, EventArgs e)
{
int i=0;
this.setAllProgress(setprogress.spStart,ref i);
}
private void Form2_FormClosed(object sender, FormClosedEventArgs e)
{
this.setAllThread(setThread.stAbort);
}
}
}