Threads

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับ thread และวิธีการใช้งาน thread ในภาษา C#

Thread คืออะไร

Thread เป็นการทำงานของโปรแกรมที่สามารถทำงานแบบ concurrence (แบบขนาน) โดยแต่ละ thread จะทำงานไปพร้อมกัน โดยปกติการทำงานของโปรแกรมนั้นจะทำงานทีละบรรทัด และต้องรอให้บรรทัดก่อนหน้าเสร็จก่อน โปรแกรมจึงจะประมวลผลในบรรทัดต่อไป

การใช้ thread นั้นสามารถทำให้โปรแกรมทำงานพร้อมกันได้ในแต่ละ thread ที่ถูกสร้างขึ้นภายในโปรแกรม ตัวอย่างการใช้งาน มักจะพบในโปรแกรมที่สามารถแบ่งงานกันทำได้ หรือโปรแกรม server และ client โดยที่ server จะสร้าง thread ขึ้นมาเพื่อจัดการกับแต่ละ client ที่เชื่อมต่อเข้ามา และใช้กับการพัฒนาเกม เป็นต้น

การสร้าง Thread

ในภาษา C# มีไลบรารี่ของ thread ที่เราสามารถใช้งาน มาดูตัวอย่างการสร้าง thread

using System;
using System.Threading;

class Threads
{
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(Thread1));
Thread t2 = new Thread(new ThreadStart(Thread2));

t1.Start();
t2.Start();
}

static void Thread1() {
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Thread 1");
}
}

static void Thread2()
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("Thread 2");
}
}
}

ในตัวอย่าง เราได้สร้าง 2 thread สำหรับการแสดงผลภายใน thread การใช้ thread นั้นจะต้องนำเข้าไลบรารี่ของมันด้วยคำสั่ง using System.Threading; และเราได้สร้างสอง thread ขึ้นมาและคลาสนี้มีพารามิเตอร์คือคลาส ThreadStart ซึ่งมีพารามิเตอร์เป็น delegate สำหรับใส่ชื่อเมธอดเข้าไปเพื่อให้ thread ทำงาน

Thread t1 = new Thread(new ThreadStart(Method1));
Thread t2 = new Thread(new ThreadStart(Method2));

เราเริ่มต้นให้ thread ทำงานโดยการใช้เมธอด Start() และเราสามารถหยุดการทำงานของ thread ได้ถ้าหากต้องการโดยใช้เมธอด Abort()

Thread 1
Thread 1
Thread 1
Thread 2
Thread 2
Thread 2
Thread 2
Thread 2
Thread 1
Thread 1

นี่น่าจะเป็นผลลัพธ์ของโปรแกรม เพราะว่า thread ทำงานแบบขนานกัน ทำให้ผลลัพธ์นั้นไม่เป็นตามลำดับ เมื่อคุณรันโปรแกรมผลลัพธ์อาจจะแตกต่างกันในการรันแต่ละครั้ง

Pass parameters to Thread

ต่อไปเป็นเราจะสร้าง thread ที่สามารถให้เมธอดส่งพารามิเตอร์ได้ โดยที่เราจะส่งพารามิเตอร์เพื่อนำไปใช้ในเมธอดของ thread ดังตัวอย่างข้างล่าง

using System;
using System.Threading;

class ThreadParameter
{
static void Main(string[] args)
{
Thread thread1 = new Thread(Hello);
thread1.Start("Marcus");

Parameter param = new Parameter();
param.name = "Bob";
param.word = "How are you going?";

Thread thread2 = new Thread(Question);
thread2.Start(param);
}

static void Hello (object name)
{
Console.WriteLine("Hello " + name);
}

static void Question (object data) {
Parameter param = (Parameter) data;
Console.WriteLine(param.name + ", " + param.word);
}

class Parameter {
public string name;
public string word;
}
}

ในตัวอย่างเราได้สร้าง thread ขึ้นมาสอง thread และในเมธอด Start() เพื่อเริ่มการทำงาน thread เราสามารถส่งพารามิเตอร์ที่เป็นออบเจ็คชนิดใดก็ได้เพียงแค่ 1 ออบเจ็คเท่านั้น

thread1.Start("Marcus");
...
thread2.Start(param);

เหมือนที่คุณเห็น เราสามารถส่งได้เพียงแค่ 1 ออบเจ็คสำหรับเมธอด Start() ถ้าหากต้องการส่งหลายค่าเราต้องส่งเป็นออบเจ็คเหมือนใน thread2 และในเมธอด Hello() และ Question() สามารถมีพารามิเตอร์ได้เป็นแค่ประเภท object

Hello Marcus
Bob, How are you going?

นี่เป็นผลลัพธ์ของโปรแกรม

Multi-threaded example

ต่อไปมาดูตัวอย่างเพิ่มเติมเกี่ยวกับการใช้ thread ในภาษา C# ซึ่งเป็นโปรแกรมในการแสดงค่าของจำนวนเฉพาะตั้งแต่ 1 - n โดยโปรแกรมจะสร้าง thread ตามจำนวน logical processor ของเครื่องของคุณ โดยแต่ละ thread จะช่วยกันในการคำนวณเลขจำนวนเฉพาะและแสดงผลออกทางหน้าจอ

using System;
using System.Threading;

class MultiThreadExample
{
static int MAX_NUMBER = 100;
static int proceed_number = 1;

static void Main(string[] args)
{
// Get number of logical processor from CPU
int NUM_THREAD = Environment.ProcessorCount;
for (int i = 0; i < NUM_THREAD; i++)
{
Thread t = new Thread(delegate() {
int threadID = (int) AppDomain.GetCurrentThreadId();

while (proceed_number <= MAX_NUMBER)
{
int n = proceed_number++;
if (IsPrime(n))
{
Console.WriteLine("Thread " + threadID + " -> " + n + " is prime.");
}
else {
Console.WriteLine("Thread " + threadID + " -> " + n + " is not prime.");
}
}
});
t.Start();
}
}

static bool IsPrime(int number)
{
for (int i = 2; i < number; i++)
{
if (number % i == 0 && i != number) return false;
}
return true;
}
}

ในตัวอย่างเป็นการสร้าง thread แบบไดนามิกส์จากจำนวน logical process ของเครื่องคอมพิวเตอร์ที่ใช้รันโปรแกรมนี้

int NUM_THREAD = Environment.ProcessorCount;

และเรายังสร้าง delegate เมธอดซึ่งเป็น anonymous method ในการเป็นพารามิเตอร์ให้ thread ทำงาน นี่ทำให้เราไม่ต้องไปสร้างเมธอดไว้คนละที่

delegate() {
...
}

จากโปรแกรมด้านบน เป็นแค่พื้นฐานในการใช้ thread เท่านั้น ในตัวอย่างมันยังไม่ปลอดภัยเพียงพอ เพราะว่า thread ที่สร้างขึ้นมานั้นมีโอกาสที่จะอ่านค่า proceed_number ค่าเดียวกันในช่วงเวลาใดๆ ก็ได้ ดังนั้นคุณต้องทำการควบคุมการเข้าถึงข้อมูลพร้อมกัน (Reach condition) โดยการใช้วิธี Concurrency control ในแบบที่เหมาะสมกับการทำงานของ thread ที่คุณสร้างขึ้น ซึ่งอยู่นอกเหนือเนื้อหาในบทเรียนนี้

ในบทเรียนนี้ คุณได้เรียนรู้วิธีการสร้าง thread ในภาษา C# และการใช้งานในเบื้องต้น


บทความเกี่ยวกับ Threads

Threads ในภาษา Visual Basic

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับการใช้งาน Thread ในภาษา Visual Basic เราจะมาสร้างโปรแกรมที่สามารถทำงานได้พร้อมกันหลาย Thread หรือการเขียนโปรแกรมแบบ Multithread...