Threads

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

Thread คืออะไร

เมื่อโปรแกรมเริ่มทำงาน Common language runtime (CLR) จะทำการสร้าง Thread หนึ่งขึ้นมาอัตโนมัติ เราเรียกว่า Thread หลักหรือ Main thread ของโปรแกรม โดยมันจะทำงานอยู่เบื้องหลัง ในภาษา Visual Basic คุณสามารถสร้าง Thread ได้หลายๆ Thread โดยแต่ละ Thread จะทำงานแบบไม่พร้อมกัน (Asynchronous)

ข้อได้เปรียบในการใช้ Thread คือการที่โปรแกรมสามารถทำงานได้พร้อมกันหลายๆ อย่าง ยกตัวอย่างเช่น คุณต้องการล้างรถและซักผ้า คุณจะต้องทำอย่างหนึ่งให้เสร็จจึงจะทำสิ่งต่อไปได้ ในขณะที่ใช้ Thread คุณจะสามารถล้างรถและซักผ้าพร้อมกันได้

Thread มักจะนำไปใช้กับโปรแกรมที่ต้องทำงานพร้อมกันเพื่อให้มีประสิทธิภาพสูงสุด เช่น Parallel programming, Multi-core programming หรือในงานที่สามารถแบ่งงานกันทำได้ เช่น โปรแกรมสำหรับ Render วิดีโอสามารถให้แต่ละ Thread ทำงานแต่ละส่วนค่อยนำมารวมกันได้ ซึ่งทำให้เพิ่มความเร็วขึ้นมาสำหรับ Multi-core programming

การสร้าง Thread

ต่อไปมาดูตัวอย่างการสร้าง Thread ในภาษา Visual Basic โดยการทำงานของ Thread นั้นมักจะเกี่ยวข้องกับ Delegates ในการกำหนดฟังก์ชันสำหรับการทำงานของ Thread

Imports System.Threading

Module ThreadExample

    Sub Main()

        Dim trd As New Thread(AddressOf ThreadTask)
        trd.IsBackground = False
        trd.Start()

    End Sub

    Sub ThreadTask()
        Console.WriteLine("This message from a thread")
    End Sub

End Module

ในตัวอย่าง เป็นการสร้าง Thread อย่างง่ายจากคลาส Thread โดยคลาสนี้ให้เราจัดการสิ่งๆ ต่างเกี่ยวกับ Thread ได้ทั้งหมด

Dim trd As New Thread(AddressOf ThreadTask)

ในคำสั่งแรก เป็นการสร้างตัวแปร Thread trd เราใช้ Delegate ในการกำหนดฟังก์ชัน ThreadTask() ให้เป็นฟังก์ชันการทำงานของ Thread ดังกล่าว

trd.IsBackground = False
trd.Start()

เรากำหนดค่า False ให้กับ property IsBackground หมายความว่าให้ Thread นี้ไม่ทำงานในเบื้องหลัง โดยพื้นฐานมันมีค่าเป็น False อยู่แล้ว หลังจากนั้นเรียกใช้เมธอด trd.Start() สำหรับเริ่มการทำงานของ Thread

This message from a thread

นี่เป็นผลลัพธ์ของโปรแกรม ซึ่ง Thread จะทำงานในฟังก์ชันที่เราได้กำหนดให้กับมันในตอนแรก

เพื่อหยุดการทำงานของ Thread คุณสามารถใช้เมธอด trd.Abort() แต่สำหรับในตัวอย่างเมื่อ Thread ทำงานเสร็จสิ้นแล้วมันจะปิดการทำงานโดยอัตโนมัติ เพราะว่าการทำงานในฟังก์ชัน ThreadTask() ของเราไม่ได้เป็นแบบ Infinity loop

การเขียนโปรแกรมแบบ Multithreading

ในตัวอย่างก่อนหน้า คุณได้รู้วิธีการสร้าง Thread ไปแล้ว ต่อไปเราจะมาเขียนโปรแกรมที่ใช้ความสามารถของ Thread อย่างแท้จริงคือการใช้หลายๆ Thread ในการทำงานหลายอย่างพร้อมๆ กัน

Imports System.Threading

Module MultithreadExample

    Dim trdRead As Thread
    Dim trdSend As Thread

    Sub Main()

        trdRead = New Thread(AddressOf ThreadRead)
        trdRead.Start()

        trdSend = New Thread(AddressOf ThreadSend)
        trdSend.Start()

    End Sub

    Sub ThreadRead()
        While True
            Console.WriteLine("Read data from network stream")
            Thread.Sleep(2000)
        End While
    End Sub

    Sub ThreadSend()
        While True
            Dim c As Char = Console.ReadKey().KeyChar
            Console.WriteLine("Send {0} to network stream ", c)

            If c = "0"c Then
                trdRead.Abort()
                trdSend.Abort()
            End If
        End While
    End Sub

End Module

ในตัวอย่าง เราได้เขียนโปรแกรมสำหรับจำลองการส่งข้อมูลใน Network โดยเราสร้าง Thread สำหรับการส่งข้อมูลและรับข้อมูล

Dim trdRead As Thread
Dim trdSend As Thread

เราประกาศตัวแปร Thread สำหรับการรับข้อมูลและการส่งข้อมูลตามลำดับ

trdRead = New Thread(AddressOf ThreadRead)
 trdRead.Start()

trdSend = New Thread(AddressOf ThreadSend)
trdSend.Start()

เรากำหนดฟังก์ชันการทำงานให้กับ Thread และสั่งให้ Thread เริ่มทำงาน เมื่อสิ้นสุดคำสั่งนี้ ฟังก์ชันทั้งสองจะทำงานไปพร้อมๆ กัน

Sub ThreadRead()
    While True
        Console.WriteLine("Read data from network stream")
        Thread.Sleep(2000)
    End While
End Sub

ในฟังก์ชัน ThreadRead() เป็นการจำลองรับข้อมูลจาก Network ในทุกๆ สองวินาที เมธอด Thread.Sleep() สำหรับหน่วงเวลาการทำงานของโปรแกรมในหน่วนมิลลิวินาที

Sub ThreadSend()
    While True
        Dim c As Char = Console.ReadKey().KeyChar
        Console.WriteLine("Send {0} to network stream ", c)

        If c = "0"c Then
            trdRead.Abort()
            trdSend.Abort()
        End If
    End While
End Sub

ในฟังก์ชัน ThreadSend() เป็นการจำลองส่งข้อมูลไปใน Network โดยรับค่าทางคีย์บอร์ดและส่งไปทันที เรายังตรวจสอบถ้าหากค่าที่รับมานั้นเป็น 0 เราจะหยุดการทำงานของ Thread ทั้งหมด

Read data from network stream
Read data from network stream
Read data from network stream
aSend a to network stream
Read data from network stream
Read data from network stream
bSend b to network stream
Read data from network stream
Read data from network stream
Read data from network stream
3Send 3 to network stream
Read data from network stream
0Send 0 to network stream

นี่เป็นผลลัพธ์การทำงานของโปรแกรม ซึ่งโปรแกรมจะแสดงข้อความ Read data from network stream ทุกๆ สองวินาที ในขณะเดียวกันเรายังสามารถรับค่าจากคีย์บอร์ดเพื่อที่จะส่งข้อมูลได้ และ Thread ทั้งสองจะหยุดการทำงานเมื่อกดปุ่ม 0

Passing parameters to thread

ในตัวอย่างก่อนหน้า เราได้ใช้ Delegate ในการกำหนดฟังก์ชันการทำงานให้กับ Thread ต่อไปเราจะส่งพารามิเตอร์ไปยัง Thread เพื่อนำค่าไปใช้งานภายใน Thread

Imports System.Threading

Module ThreadParameters

    Sub Main()

        For i = 1 To 10
            Dim p As New Parameter
            p.number = i

            Dim thr As New Thread(AddressOf DispayNumber)
            thr.Start(p)
        Next

    End Sub

    Sub DispayNumber(ByVal param As Parameter)
        Console.WriteLine("Thread " & param.number)
    End Sub

End Module

Class Parameter
    Public number As Integer
End Class

ในตัวอย่างเราได้สร้างคลาส Parameter สำหรับเป็นพารามิเตอร์ในการส่งข้อมูลเข้าไปใน Thread เราใช้คำสั่ง For loop ในการสร้าง 10 Thread ขึ้นมา

thr.Start(p)

นี่เป็นคำสั่งที่เราส่งออบเจ็ค p ซึ่งประกอบไปด้วยหมายเลขของ Thread โดยใส่เป็นพารามิเตอร์ของเมธอด thr.Start() และในฟังก์ชัน

Thread 1
Thread 4
Thread 3
Thread 2
Thread 5
Thread 6
Thread 7
Thread 8
Thread 9
Thread 10

นี่เป็นผลลัพธ์การทำงานของโปรแกรม ซึ่งตัวเลขจะไม่เรียงลำดับเพราะว่าการทำงานในแต่ละ Thread นั้นอาจจะใช้เวลาแตกต่างกัน ซึ่งขึ้นกับการทำงานของคอมพิวเตอร์ในตอนนั้น

นี่เป็นเพียงแค่ตัวอย่างพื้นฐานของ Thread เท่านั้น ซึ่งการทำงานกับ Thread นั้นมีเรื่องที่คุณจะต้องศึกษาอีกมากมาย เพราะว่า Thread นั้นทำงานพร้อมกัน มันเป็นไปได้ที่จะเกิดการอ่านหรือเขียนข้อมูลในเวลาเดียวกัน (Race condition) ซึ่งใน .Net framework ได้มีไลบรารี่มาตรฐานสำหรับจัดการเช่น Mutexes, Condition variables, Critical sections, Semaphores หรือวิธีอื่นๆ

ในบทนี้ คุณได้เรียนรู้และเข้าใจเกี่ยวกับการใช้งาน Thread ในภาษา Visual Basic และแนวคิดการพัฒนาโปรแกรมแบบ Multithreading