Most popular

วันจันทร์ที่ 2 พฤษภาคม พ.ศ. 2554

จัดการ C# Multi-Threading GUI เพื่อการใช้งานจริง (PART I)

จากตอนที่แล้ว "ประยุคใช้ C# Threading แยก Process การทำงานของโปรแกรมแบบ GUI"
ตอนนี้ผู้เขียนจะอธิบายการใช้ Thread มากกว่า 1 Thread ในที่นี้ผู้เขียนไม่นับ Thread ของโปรแกรม GUI ที่ต้องมีอยู่แล้ว
ผู้เขียนได้เพิ่มการทำงานจากตัวอย่างที่แล้ว โดยให้ทำการเพิ่มข้อมูลใส่ใน ListBox หลายตัว โดยออกแบบฟอร์ม ดังนี้
บนฟอร์มจะมี ListBox ทั้งหมด 4 ตัวและมีปุ่ม Start 1 ปุ่มคือ Button1
จากนั้นผู้เขียนจะทำการดัดแปลง method fillList ให้มีความยืดหยุ่นสูง เพื่อสามารถใช้ทำงานได้โดยหลายๆ Thread

void fillList(object obj)
{
      Invoke((MethodInvoker)delegate
      {
            int i = 0;

            // Parameter ที่ส่งเข้ามาเป็นแบบ array ในที่นี้ให้ index ที่ 0 คือ Control ListBox
            ListBox lb = (ListBox)((object[])obj)[0];


             // Parameter ที่ส่งเข้ามาเป็นแบบ array ในที่นี้ให้ index ที่ 1 คือ ค่าสูงสุดที่ต้องการให้วนลูป 
            int max = (int)((object[])obj)[1];
            while (true)
            {
                 i++;
                 lb.Items.Add(i);
                 if (i == max)
                         break;
            }
        });
}


ที่ปุ่ม Start นั้นให้เรียกใช้ Thread 2 ตัว เพื่อใส่ค่าให้ LisBox1 และ ListBox2
private void button1_Click(object sender, EventArgs e)
{
    Thread t = new Thread(fillList);
     t.Start(new object[]{listBox1,DateTime.Now.Year+543});
//ส่ง Parameter ที่มีรูปแบบเป็น array

    Thread x = new Thread(fillList);
    x.Start(new object[] { listBox2,
DateTime.Now.Year});  //ส่ง Parameter ที่มีรูปแบบเป็น array
}


จะเห็นว่าเมื่อทั้ง 2 Thread ทำงานกับ method fillList ก็จะมีการส่ง Parameter เป็น array ไปให้ด้วย
โดยที่มีการสร้าง object เป็น array แล้วส่งค่าไปในทันที
ผลที่ได้ก็คือ ListBox ทั้ง 2 ตัวจะทำงานพร้อมกัน โดยที่ ListBox1 จะถูกวนลูปตั้งแต่ 1 จนถึงปี พ.ศ. ปัจจุบัน ส่วน ListBox 2   จะถูกวนลูปตั้งแต่ 1 จนถึงปี ค.ศ. ปัจจุบัน  ดังภาพ
การทำงานของทั้ง 2 Thread นั้นมีการทำงานคล้ายกัน และทำไปพร้อมๆกัน อย่างเป็นอิสระไม่รอกัน จึงไม่หน่วงการทำงานของฟอร์มซึ่งก็คืออีก Thread นั่นเอง

Multi - threading ทำงานตามลำดับ โดยใช้ join(timeout)
ใน Thread แต่ละตัวที่สร้างขึ้นจะมี method join เพื่อให้ใช้สำหรับบอกให้ thread ทำงานต่อเมื่อถึงเวลาของตน
โดยปกติ join ต้องการค่า Parameter เป็น เวลา timeout จะเป็น milliseconds หรือ Timespan ก็ได้ เพื่อหลังจากครบเวลาจะให้ Thread ทำงานได้
เพื่อให้เห็นการทำงานอย่างชัดเจน ผู้เขียนได้ลองปรับปรุงการแสดงผลของ method fillList ดังนี้

void fillList(object obj)
{
      Invoke((MethodInvoker)delegate
      {
               int i = 0;
               ListBox lb = (ListBox)((object[])obj)[0];
               int max = (int)((object[])obj)[1];
               while (true)
              {
                   i++;
                   lb.Items.Add(i);


                   //เพิ่มส่วนนี้เข้าไปเพื่อให้เห็นการทำงานของ Thread กับ ListBox ได้ชัดเจน
                   
lb.SelectedIndex = lb.Items.Count - 1;
                   lb.Update();


                   if (i == max)
                         break;
               }
      });
}


 จากนั้นใช้ Thread ทั้งหมด 3 ตัวเพื่อเพิ่มข้อมูลให้กับ ListBox1 , ListBox2 และ ListBox3
โดยปรับปรุ่ง Code ที่ปุ่ม Start ดังนี้

Thread t = new Thread(fillList);
Thread x = new Thread(fillList);
Thread h = new Thread(fillList);

t.Start(new object[]{listBox1,5000});
t.Join(0);  //ให้ Thread t เริ่มทำงานทันที

x.Start(new object[] { listBox2, 550});
x.Join(2000);   //ให้ Thread x ทำงานภายใน 2 วินาที

h.Start(new object[] { listBox3, 3790 });

เมื่อกดปุ่ม Start
Thread t และ x จะทำงานตามคำสั่ง join ที่มีเวลา timeout เป็นตัวกำหนด จะได้ผลตามภาพด้านล่างนี้

2 ความคิดเห็น:

  1. ไม่ระบุชื่อ13 พฤษภาคม 2554 เวลา 01:21

    มีวิธี ให้เทรด แต่ละตัวทำงานตามตัวอย่างแต่ ตัว ui ยังสามารถขยับได้ไหมครับ

    ตอบลบ
  2. ถ้าหมายถึงการให้ event ต่างๆยังทำงานอยู่ในขณะที่วนลูป ก็มีอยู่ 2 วิธีครับ
    คือ การใส่ Application.DoEvents(); ไว้ในลูป
    หรือการใช้ Method Invoke ก้ได้ครับ

    ตอบลบ