ลองนึกภาพว่าเรากับเพื่อนกำลังจะกดจองตั๋วคอนเสิร์ตใบสุดท้ายพร้อมๆ กัน ใครที่กดได้ก่อนก็จะได้ตั๋วไป แต่ถ้าทั้งคู่กดพร้อมกันเป๊ะๆ ระบบจะรู้ได้อย่างไรว่าใครควรได้ตั๋วไป?

นี่แหละ คือ ตัวอย่างง่ายๆ ของ Race Condition ในโลกของโปรแกรมเมอร์

Race Condition จะเกิดขึ้นเมื่อ

ผลลัพธ์ของโปรแกรมขึ้นอยู่กับลำดับการทำงานของ Thread (ชุดคำสั่งย่อยๆ ของโปรแกรม) ซึ่งเราไม่สามารถควบคุมได้เลยว่า Thread ไหนจะทำงานเสร็จก่อนกัน

ตัวอย่าง

สมมติว่าเรามีตัวแปรชื่อ counter ที่มีค่าเริ่มต้นเป็น 0 และมีสอง Thread ที่จะเพิ่มค่า counter ขึ้นไป 100 ครั้ง

สิ่งที่ควรจะเป็น:

  • Thread 1 เพิ่ม counter 100 ครั้ง
  • Thread 2 เพิ่ม counter 100 ครั้ง
  • ค่าสุดท้ายของ counter ควรจะเป็น 200

แต่สิ่งที่อาจเกิดขึ้น (Race Condition):

  1. Thread 1 อ่านค่า counter (ซึ่งมีค่า 0)
  2. ก่อนที่ Thread 1 จะเขียนค่ากลับเข้าไป, Thread 2 ก็อ่านค่า counter (ซึ่งก็ยังมีค่า 0 เหมือนกัน)
  3. Thread 1 เพิ่มค่าในหน่วยความจำของมันเป็น 1 แล้วเขียนกลับเข้าไปใน counter (ตอนนี้ counter มีค่า 1)
  4. 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 แข่งกันเข้าถึงข้อมูล จนทำให้ผลลัพธ์ของโปรแกรมไม่เป็นไปตามที่เราคาดหวัง และการแก้ไขคือการจัดการให้การเข้าถึงข้อมูลนั้นเป็นระเบียบและปลอดภัย