ลองนึกภาพว่าเรากับเพื่อนกำลังจะกดจองตั๋วคอนเสิร์ตใบสุดท้ายพร้อมๆ กัน ใครที่กดได้ก่อนก็จะได้ตั๋วไป แต่ถ้าทั้งคู่กดพร้อมกันเป๊ะๆ ระบบจะรู้ได้อย่างไรว่าใครควรได้ตั๋วไป?
นี่แหละ คือ ตัวอย่างง่ายๆ ของ Race Condition ในโลกของโปรแกรมเมอร์
Race Condition จะเกิดขึ้นเมื่อ
ผลลัพธ์ของโปรแกรมขึ้นอยู่กับลำดับการทำงานของ Thread (ชุดคำสั่งย่อยๆ ของโปรแกรม) ซึ่งเราไม่สามารถควบคุมได้เลยว่า Thread ไหนจะทำงานเสร็จก่อนกัน
ตัวอย่าง
สมมติว่าเรามีตัวแปรชื่อ counter ที่มีค่าเริ่มต้นเป็น 0 และมีสอง Thread ที่จะเพิ่มค่า counter ขึ้นไป 100 ครั้ง
สิ่งที่ควรจะเป็น:
- Thread 1 เพิ่ม counter 100 ครั้ง
- Thread 2 เพิ่ม counter 100 ครั้ง
- ค่าสุดท้ายของ counter ควรจะเป็น 200
แต่สิ่งที่อาจเกิดขึ้น (Race Condition):
- Thread 1 อ่านค่า counter (ซึ่งมีค่า 0)
- ก่อนที่ Thread 1 จะเขียนค่ากลับเข้าไป, Thread 2 ก็อ่านค่า counter (ซึ่งก็ยังมีค่า 0 เหมือนกัน)
- Thread 1 เพิ่มค่าในหน่วยความจำของมันเป็น 1 แล้วเขียนกลับเข้าไปใน counter (ตอนนี้ counter มีค่า 1)
- Thread 2 ก็เพิ่มค่าในหน่วยความจำของมันเป็น 1 แล้วเขียนกลับเข้าไปใน counter (ตอนนี้ counter ก็ยังคงมีค่า 1)
ผลที่ได้: แทนที่จะได้ค่าเป็น 2 โปรแกรมกลับได้ค่าเป็น 1 เพราะทั้งสอง Thread ทำงานทับซ้อนกัน
Data Race
นอกจากตัว Race Condition แล้ว หลายๆ คนอาจจะเคยได้ยิน คำว่า Data Race ซึ่งเป็นสถานการณ์ที่หน่วยความจำเดียวกันถูกแชร์ระหว่าง Thread หลาย Thread ซึ่งจะมีอย่างน้อย 1 Thread จะมีการเปลี่ยนแปลง (การเข้าถึงการเขียน) โดยไม่มีการ synchronization
มันทำให้เกิดปัญหาเหมือนๆ กัน คือ การแทนที่ของข้อมูล
วิธีแก้ไข Race Condition
ปัญหา Race Condition สามารถแก้ไขได้หลายวิธี ขึ้นอยู่กับภาษาและบริบทการใช้งาน แต่หลักการพื้นฐาน คือ การทำให้การเข้าถึงข้อมูลเป็นแบบ Atomic Operation หรือ การทำงานที่ต้องเสร็จสิ้นสมบูรณ์ในครั้งเดียว ไม่มีการถูกขัดจังหวะจาก Thread อื่นๆ
วิธีที่นิยมใช้ได้แก่:
Locks: ใช้การล็อกข้อมูลเพื่อไม่ให้ Thread อื่นเข้าถึงได้ในขณะที่ Thread หนึ่งกำลังทำงานอยู่ เหมือนกับการล็อกประตูห้องน้ำ เมื่อมีคนเข้าอยู่ คนอื่นก็ต้องรอ
Semaphores: เป็นเครื่องมือที่คล้ายกับ Locks แต่สามารถกำหนดจำนวน Thread ที่จะเข้าถึงข้อมูลพร้อมกันได้
Atomic Operations: ใช้ฟังก์ชันหรือไลบรารีที่ถูกออกแบบมาเพื่อการทำงานที่ปลอดภัยจาก Race Condition โดยเฉพาะ
การทำความเข้าใจและแก้ไขปัญหา Race Condition เป็นสิ่งสำคัญมากในการพัฒนาซอฟต์แวร์ เพราะหากปล่อยทิ้งไว้ อาจส่งผลให้โปรแกรมทำงานผิดพลาด, ข้อมูลเสียหาย, หรือเกิดช่องโหว่ด้านความปลอดภัยได้
สรุปง่ายๆ Race Condition คือภาวะที่ Thread แข่งกันเข้าถึงข้อมูล จนทำให้ผลลัพธ์ของโปรแกรมไม่เป็นไปตามที่เราคาดหวัง และการแก้ไขคือการจัดการให้การเข้าถึงข้อมูลนั้นเป็นระเบียบและปลอดภัย