แย่ที่สุด (ใช้งานไม่ได้จริง)
เปลี่ยน accessifier ของcounterเป็นpublic volatile
อย่างที่คนอื่น ๆ พูดถึงสิ่งนี้ด้วยตัวของมันเองไม่ได้ปลอดภัยอะไรเลย ประเด็นvolatileก็คือว่ามีหลายเธรดที่ทำงานบน CPU หลายตัวสามารถและจะแคชข้อมูลและคำสั่งซื้อซ้ำ
หากไม่ใช่ volatileและ CPU A เพิ่มค่าหน่วยความจำ CPU B อาจไม่เห็นค่าที่เพิ่มขึ้นจริงจนกระทั่งบางครั้งในภายหลังซึ่งอาจทำให้เกิดปัญหา
หากเป็นvolatileเช่นนี้จะช่วยให้มั่นใจว่าทั้งสองซีพียูสามารถดูข้อมูลเดียวกันได้ในเวลาเดียวกัน มันไม่ได้หยุดพวกเขาจากการสอดแทรกการอ่านและการเขียนซึ่งเป็นปัญหาที่คุณพยายามหลีกเลี่ยง
อันดับสอง:
lock(this.locker) this.counter++;
วิธีนี้ปลอดภัยที่จะทำ (หากคุณจำได้ในlockทุกที่ที่คุณเข้าถึงthis.counter) จะป้องกันไม่ให้กระทู้อื่น ๆ lockerจากการดำเนินการรหัสอื่นใดที่จะรักษาโดย การใช้ตัวล็อคยังช่วยป้องกันปัญหาการเรียงลำดับใหม่ของ CPU แบบหลายจุดซึ่งดีมาก
ปัญหาคือล็อคช้าและถ้าคุณใช้lockerในที่อื่นที่ไม่เกี่ยวข้องจริงๆคุณสามารถปิดกั้นเธรดอื่น ๆ ได้โดยไม่มีเหตุผล
ดีที่สุด
Interlocked.Increment(ref this.counter);
วิธีนี้ปลอดภัยเนื่องจากการอ่านเพิ่มและเขียนใน 'หนึ่งครั้ง' อย่างมีประสิทธิภาพซึ่งไม่สามารถถูกขัดจังหวะได้ ด้วยเหตุนี้จึงไม่ส่งผลกระทบต่อรหัสอื่น ๆ และคุณไม่จำเป็นต้องจำที่จะล็อคที่อื่นเช่นกัน นอกจากนี้ยังเร็วมาก (อย่างที่ MSDN บอกว่าสำหรับซีพียูสมัยใหม่นี่มักจะเป็นคำสั่ง CPU เพียงตัวเดียว)
ฉันไม่แน่ใจทั้งหมด แต่ถ้ามันได้รับรอบ CPU อื่น ๆ เรียงลำดับสิ่งต่าง ๆ หรือถ้าคุณยังต้องรวมความผันผวนกับการเพิ่มขึ้น
InterlockedNotes:
- วิธีที่ถูกล็อคจะปลอดภัยอย่างต่อเนื่องในจำนวนแกนหรือซีพียูใด ๆ
- วิธีการเชื่อมต่อใช้รั้วเต็มรอบคำแนะนำพวกเขาดำเนินการดังนั้นการสั่งซื้อใหม่จะไม่เกิดขึ้น
- ไม่จำเป็นต้องใช้วิธีการที่เชื่อมต่อกันหรือแม้กระทั่งไม่สนับสนุนการเข้าถึงเขตข้อมูลที่มีความผันผวนเนื่องจากความผันผวนจะถูกวางครึ่งรั้วรอบการดำเนินการในสนามที่กำหนด
เชิงอรรถ: ความผันผวนที่ดีจริงๆ
เช่นเดียวกับที่volatileไม่ได้ป้องกันปัญหาการมัลติเธรดเหล่านี้มันมีไว้เพื่ออะไร? ตัวอย่างที่ดีคือการพูดว่าคุณมีสองกระทู้หนึ่งซึ่งมักจะเขียนถึงตัวแปร (พูดqueueLength) และหนึ่งที่มักจะอ่านจากตัวแปรเดียวกันนั้น
หากqueueLengthไม่ระเหยเธรด A อาจเขียนห้าครั้ง แต่เธรด B อาจเห็นการเขียนเหล่านั้นว่าล่าช้า (หรืออาจเกิดขึ้นในลำดับที่ไม่ถูกต้อง)
วิธีแก้ปัญหาคือล็อค แต่คุณสามารถใช้ความผันผวนในสถานการณ์นี้ได้ สิ่งนี้จะช่วยให้มั่นใจได้ว่าเธรด B จะเห็นสิ่งที่ทันสมัยที่สุดเสมอที่เธรด A เขียนไว้ โปรดทราบว่าตรรกะนี้ใช้ได้เฉพาะในกรณีที่คุณมีนักเขียนที่ไม่เคยอ่านและผู้อ่านที่ไม่เคยเขียนและหากสิ่งที่คุณเขียนเป็นค่าอะตอมมิก ทันทีที่คุณอ่าน - แก้ไข - เขียนเดียวคุณจะต้องไปที่การดำเนินการ Interlocked หรือใช้ล็อค