การใช้ Invoke กับ delegate เป็นตัวอย่างที่ดีที่สุด เพราะง่ายและชัดเจน ซึ่งเป็นวิธีที่ผู้เขียนใช้ทดสอบ
ตัวของ delegate method ที่มีการใช้ BeginInvoke นั้นจะสามารถทำงานพร้อมๆกันหลายๆ method ได้ โดยที่ไม่มีการรอกัน เป็นการทำงาน Multi-Threading อีกแบบนึงที่ใช้ได้ดี คำสั่ง BeginInvoke จะทำการแยก Thread ออกจาก Common Language Runtime (CLR) และโดนจัดการด้วย Thread pool จึงทำให้แต่ละ delegate method ทำงานได้อย่างอิสระต่อกัน และ Thread ที่เกิดจากการใช้ Invoke สามารถมีได้ถึง 25 Thread ในการทำงานพร้อมกันบน Processor ตัวเดียว
ผู้เขียนได้ออกแบบฟอร์มเพื่อทดสอบตามรูปด้านล่างนี้
การทำงานของโปรแกรมก็คือ เมื่อกดปุ่ม Run จะให้มีการวนลูปสุ่มชื่อเพื่อน เข้าไปใน ListBox โดยที่ ListBox ด้านขวามือจะให้ "Hello" ส่วนด้านซ้ายมือจะให้ "Bye"
ในส่วน Member ของ Class Form1 ผู้เขียนจะประกาศ delegate method และรายชื่อของเพื่อนในรูปแบบ array
private delegate void showMS(string txt,ListBox l);
private string[] friends = {"David","Ryan","Adam","Briony","Harry","Sara",
"Peter","Maria","Natacha","Lydia","Nina","Macha",
"Maggy","Victoria","Naomi"};
ต่อมาคือ method ที่ใช้กับ delegate ที่ประกาศไว้
method นี้จะมี Parameter 2 ตัวคือ string และ ListBox
private void mess(string str,ListBox lb)
{
lb.Items.Clear(); //ล้าง ListBox
int i=0;
while (i < 2000)
{
//สุ่มชื่อเพื่อนขึ้นมา
string fName = friends[new Random().Next(0, friends.Length)];
lb.Items.Add(str + " " + fName);
lb.SelectedIndex = i;
i++;
}
}
จากนั้นก็มาถึงคำสั่งที่ใช้กับปุุ่ม Run (button1)
โดยเมื่อมีการกดปุ่มแล้วจะมีการใส่ค่าลงใน ListBox ทั้ง 2 ตัวพร้อมกัน
private void button1_Click(object sender, EventArgs e)
{
//ปิดการตรวจสอบ Thread Cross
Form1.CheckForIllegalCrossThreadCalls = false;
//สร้าง delegate method
showMS sms = new showMS(mess);
//ประกาศ IAsyncResult เพื่อรับค่าสถานะจาก delegate ที่มีการ invoke
IAsyncResult helloRes = sms.BeginInvoke("Hello", this.listBox1, null, null);
IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, null, null);
}
เมื่อลองรันโปรแกรมและกดปุ่ม Run ก็จะมีการใส่ค่าใน ListBox ทั้ง 2 ตัวพร้อมๆกัน
ผู้เขียนจะสร้าง Method เพิ่มเติมเพื่อให้ทำงานเมื่อจากมีการ Callback กลับมาจากการ Invoke
- Method helloCallback : เมื่อมีการ Callback ให้แสดงข้อความ "Completed"
- Method byeCallback : เมื่อมีการ Callback ให้ทำงานซ้ำอีกรอบ และ Callback ไปที่ helloCallback
{
MessageBox.Show("Completed");
}
private void byeCallback(IAsyncResult res)
{
showMS sms = new showMS(mess);
IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, helloCallback, null);
}
และแก้ไข Code ในปุ่ม Run(button1) ให้ Invoke มี Parameter ที่เรียกใช้ Callback method
private void button1_Click(object sender, EventArgs e)
{
Form1.CheckForIllegalCrossThreadCalls = false;
showMS sms = new showMS(mess);
IAsyncResult helloRes = sms.BeginInvoke("Hello", this.listBox1, helloCallback, null);
IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, byeCallback, null);
}
จากนั้นลองทดสอบอีกครั้งจะพบว่ามีการทำงานทั้งหมด 3 รอบ คือ ใส่ข้อมูลใน ListBox คือ Hello 1 รอบ และ Bye 1 รอบ และหลังจาก ListBox ฝั่งซ้ายทำงานเสร็จสิ้นจนมีการ Callback จะทำงานต่ออีก 1 รอบก่อนที่จะจบ โดยทำงานไม่รอกัน
หมายเหตุ
(IAsyncResult helloRes = sms.BeginInvoke("Hello", this.listBox1, helloCallback, null);
IAsyncResult byeRes = sms.BeginInvoke("Bye", this.listBox2, byeCallback, null);
)
ค่าสถานะที่ได้รับจากการ Invoke มีรายละเอียดคือ
- AsyncState : สถานะการทำงานที่ต่างกันออกไป
- AsyncWaitHandle : รอ และปกป้องให้การทำงานที่ต่างกันสำเร็จ
- CompleteSynchronously : บ่งบอกว่าการทำงานที่ต่างๆกันนั้นสำเร็จ
- IsCompleted : บ่งบอกว่าการทำงานทั้งหมดเสร็จสิ้นแล้ว
ขอโค้ดตัวอย่างหน่อยได้ไหมครับ
ตอบลบ