หมายความว่าสองเธรดไม่สามารถเปลี่ยนข้อมูลพื้นฐานพร้อมกันได้หรือไม่ หรือหมายความว่าส่วนรหัสที่กำหนดจะทำงานด้วยผลลัพธ์ที่สามารถคาดการณ์ได้เมื่อมีหลายเธรดที่กำลังเรียกใช้งานส่วนรหัสนั้น
หมายความว่าสองเธรดไม่สามารถเปลี่ยนข้อมูลพื้นฐานพร้อมกันได้หรือไม่ หรือหมายความว่าส่วนรหัสที่กำหนดจะทำงานด้วยผลลัพธ์ที่สามารถคาดการณ์ได้เมื่อมีหลายเธรดที่กำลังเรียกใช้งานส่วนรหัสนั้น
คำตอบ:
จาก Wikipedia:
Thread safety เป็นแนวคิดการเขียนโปรแกรมคอมพิวเตอร์ที่ใช้ในบริบทของโปรแกรมแบบมัลติเธรด ชิ้นส่วนของรหัสนั้นปลอดภัยสำหรับเธรดหากทำงานอย่างถูกต้องระหว่างดำเนินการหลายเธรดพร้อมกัน โดยเฉพาะอย่างยิ่งต้องตอบสนองความต้องการของหลาย ๆ เธรดในการเข้าถึงข้อมูลที่ใช้ร่วมกันแบบเดียวกันและความต้องการในการเข้าถึงข้อมูลที่แบ่งปันโดยใช้เพียงหนึ่งเธรดในเวลาใดก็ตาม
มีหลายวิธีในการบรรลุความปลอดภัยของเธรด:
Re-entrancy:
การเขียนโค้ดในลักษณะที่สามารถถูกเรียกใช้งานบางส่วนโดยงานหนึ่งเข้ามาอีกครั้งโดยงานอื่นแล้วกลับมาทำงานต่อจากงานเดิม สิ่งนี้ต้องการการบันทึกข้อมูลสถานะในตัวแปรภายในแต่ละงานโดยปกติจะอยู่ในสแต็กแทนที่จะเป็นในตัวแปรสแตติกหรือโกลบอล
การยกเว้นซึ่งกันและกัน:
การเข้าถึงข้อมูลที่ใช้ร่วมกันนั้นเป็นลำดับโดยใช้กลไกที่ช่วยให้มั่นใจว่ามีเพียงหนึ่งเธรดที่อ่านหรือเขียนข้อมูลที่แชร์ได้ตลอดเวลา จำเป็นต้องใช้ความระมัดระวังเป็นอย่างยิ่งหากชิ้นส่วนของรหัสเข้าถึงข้อมูลที่ใช้ร่วมกันหลายชิ้น - ปัญหารวมถึงสภาพการแข่งขันการหยุดชะงักการเคลื่อนไหวความอดอยากและความเจ็บป่วยอื่น ๆ อีกมากมายที่ระบุไว้ในตำราระบบปฏิบัติการจำนวนมาก
การจัดเก็บภายในเธรด:
ตัวแปรถูกแปลเป็นภาษาท้องถิ่นเพื่อให้แต่ละเธรดมีสำเนาส่วนตัวของตัวเอง ตัวแปรเหล่านี้เก็บค่าข้ามรูทีนย่อยและขอบเขตรหัสอื่น ๆ และมีความปลอดภัยของเธรดเนื่องจากเป็นโลคัลสำหรับแต่ละเธรดแม้ว่าโค้ดที่เข้าถึงพวกเขาอาจเป็น reentrant
การดำเนินงานปรมาณู:
ข้อมูลที่ใช้ร่วมกันสามารถเข้าถึงได้โดยใช้การดำเนินการของอะตอมซึ่งไม่สามารถถูกขัดจังหวะโดยเธรดอื่น โดยปกติต้องใช้คำสั่งภาษาเครื่องพิเศษซึ่งอาจมีอยู่ในไลบรารีรันไทม์ เนื่องจากการดำเนินการเป็นแบบปรมาณูข้อมูลที่ใช้ร่วมกันจะถูกเก็บไว้ในสถานะที่ถูกต้องเสมอไม่ว่าเธรดอื่น ๆ จะเข้าถึงอะไร การดำเนินการปรมาณูเป็นพื้นฐานของกลไกการล็อคเกลียว
อ่านเพิ่มเติม:
http://en.wikipedia.org/wiki/Thread_safety
ในภาษาเยอรมัน: http://de.wikipedia.org/wiki/Threadsicherheit
ในภาษาฝรั่งเศส: http://fr.wikipedia.org/wiki/Threadsafe (สั้นมาก)
รหัสของเธรดที่ปลอดภัยคือรหัสที่จะทำงานแม้ว่าเธรดจำนวนมากกำลังเรียกใช้งานพร้อมกัน
คำถามที่ให้ข้อมูลเพิ่มเติมคือสิ่งที่ทำให้โค้ดไม่ได้เป็นเธรดที่ปลอดภัยและคำตอบคือมีเงื่อนไขสี่ประการที่ต้องเป็นจริง ... ลองนึกภาพโค้ดต่อไปนี้ (และการแปลภาษาด้วยเครื่อง)
totalRequests = totalRequests + 1
MOV EAX, [totalRequests] // load memory for tot Requests into register
INC EAX // update register
MOV [totalRequests], EAX // store updated value back to memory
ฉันชอบความหมายจาก Java Concurrency ในทางปฏิบัติของ Brian Goetz สำหรับความครอบคลุม
"คลาสปลอดภัยสำหรับเธรดหากทำงานอย่างถูกต้องเมื่อเข้าถึงจากหลายเธรดโดยไม่คำนึงถึงการกำหนดเวลาหรือการสอดแทรกการประมวลผลเธรดเหล่านั้นตามสภาพแวดล้อมรันไทม์และไม่มีการซิงโครไนซ์เพิ่มเติมหรือการประสานงานอื่น ๆ ในส่วนของรหัสการโทร "
ตามที่คนอื่น ๆ ได้ระบุไว้ความปลอดภัยของเธรดหมายความว่าชิ้นส่วนของรหัสจะทำงานได้อย่างไม่มีข้อผิดพลาดหากมีการใช้เธรดมากกว่าหนึ่งรายการในคราวเดียว
เป็นเรื่องที่ควรตระหนักว่าบางครั้งอาจมีค่าใช้จ่ายเวลาของคอมพิวเตอร์และการเข้ารหัสที่ซับซ้อนมากขึ้นดังนั้นจึงไม่เป็นที่ต้องการเสมอไป ถ้าคลาสสามารถใช้อย่างปลอดภัยบนเธรดเดียวเท่านั้นอาจเป็นการดีกว่าถ้าทำเช่นนั้น
ยกตัวอย่างเช่น Java มีสองชั้นเรียนที่มีค่าเท่ากันเกือบและStringBuffer
StringBuilder
ความแตกต่างคือStringBuffer
ความปลอดภัยของเธรดดังนั้นStringBuffer
อาจใช้หลายอินสแตนซ์ของเธรดเดียวในคราวเดียว StringBuilder
ไม่ปลอดภัยสำหรับเธรดและได้รับการออกแบบมาเพื่อทดแทนประสิทธิภาพที่สูงขึ้นสำหรับเคสเหล่านั้น (ส่วนใหญ่) เมื่อสร้างสตริงโดยเธรดเดียวเท่านั้น
รหัส thread-safe-code ทำงานตามที่ระบุไว้แม้ว่าจะถูกป้อนพร้อมกันโดยเธรดที่แตกต่างกัน บ่อยครั้งหมายความว่าโครงสร้างข้อมูลภายในหรือการดำเนินการที่ควรรันอย่างต่อเนื่องจะได้รับการปกป้องจากการดัดแปลงต่าง ๆ ในเวลาเดียวกัน
วิธีที่ง่ายกว่าในการทำความเข้าใจคือสิ่งที่ทำให้โค้ดไม่ปลอดภัยสำหรับเธรด มีสองประเด็นหลักที่จะทำให้แอปพลิเคชันเธรดมีพฤติกรรมที่ไม่พึงประสงค์
การเข้าถึงตัวแปรที่แชร์โดยไม่ล็อค
ตัวแปรนี้สามารถแก้ไขได้โดยเธรดอื่นในขณะที่เรียกใช้ฟังก์ชัน คุณต้องการป้องกันด้วยกลไกการล็อคเพื่อให้แน่ใจว่าพฤติกรรมของฟังก์ชั่นของคุณ กฎทั่วไปของหัวแม่มือคือการทำให้ล็อคเป็นเวลาที่สั้นที่สุด
การหยุดชะงักที่เกิดจากการพึ่งพาซึ่งกันและกันของตัวแปรที่แชร์
หากคุณมีตัวแปรที่แชร์กันสองตัวคือ A และ B ในฟังก์ชั่นหนึ่งคุณล็อค A ก่อนแล้วค่อยล็อก B ในอีกฟังก์ชันหนึ่งคุณเริ่มล็อค B และหลังจากนั้นครู่หนึ่ง เป็น deadlock ที่มีศักยภาพซึ่งฟังก์ชันแรกจะรอให้ปลดล็อค B เมื่อฟังก์ชั่นที่สองจะรอให้ปลดล็อค A ปัญหานี้อาจไม่เกิดขึ้นในสภาพแวดล้อมการพัฒนาของคุณและเป็นครั้งคราวเท่านั้น เพื่อหลีกเลี่ยงการล็อคทั้งหมดจะต้องอยู่ในลำดับเดียวกันเสมอ
ใช่และไม่.
ความปลอดภัยของเธรดนั้นมากกว่าการทำให้แน่ใจว่าการเข้าถึงข้อมูลที่คุณแบ่งปันมีเพียงหนึ่งเธรดในแต่ละครั้ง คุณต้องให้แน่ใจเข้าถึงลำดับข้อมูลที่ใช้ร่วมกันในขณะที่ในเวลาเดียวกันหลีกเลี่ยงสภาพการแข่งขัน , การติดตาย , livelocksและความอดอยากทรัพยากร
ผลลัพธ์ที่ไม่สามารถคาดเดาได้เมื่อมีหลายเธรดที่กำลังทำงานอยู่นั้นไม่ได้เป็นเงื่อนไขที่จำเป็นสำหรับรหัสของเธรดที่ปลอดภัย แต่มักเป็นผลพลอยได้ ตัวอย่างเช่นคุณสามารถตั้งค่ารูปแบบผู้ผลิต - ผู้บริโภคด้วยคิวที่ใช้ร่วมกันหนึ่งเธรดผู้ผลิตและเธรดผู้บริโภคน้อยและการไหลของข้อมูลอาจคาดเดาได้อย่างสมบูรณ์แบบ หากคุณเริ่มแนะนำผู้บริโภคมากขึ้นคุณจะเห็นผลลัพธ์การค้นหาแบบสุ่มมากขึ้น
ในสาระสำคัญสิ่งต่าง ๆ อาจผิดพลาดในสภาพแวดล้อมแบบมัลติเธรด (คำสั่งการเรียงลำดับใหม่วัตถุที่สร้างขึ้นบางส่วนตัวแปรเดียวกันมีค่าแตกต่างกันในเธรดที่แตกต่างกันเนื่องจากการแคชที่ระดับ CPU เป็นต้น)
ฉันชอบคำนิยามที่กำหนดโดยJava Concurrency ในทางปฏิบัติ :
[ส่วนของรหัส] เป็นเธรดที่ปลอดภัยหากทำงานอย่างถูกต้องเมื่อเข้าถึงจากหลายเธรดไม่ว่าการกำหนดเวลาหรือการสอดแทรกการดำเนินการของเธรดเหล่านั้นโดยสภาพแวดล้อมรันไทม์และไม่มีการซิงโครไนซ์เพิ่มเติมหรือการประสานงานอื่น ๆ รหัสโทร
โดยถูกต้องพวกเขาหมายความว่าพฤติกรรมโปรแกรมในการปฏิบัติตามข้อกำหนดของ
ตัวอย่างที่คาดหวัง
ลองนึกภาพว่าคุณใช้ตัวนับ คุณสามารถพูดได้ว่ามันทำงานอย่างถูกต้องหาก:
counter.next()
ไม่ส่งคืนค่าที่มีการส่งคืนมาก่อน (เราถือว่าไม่มีการโอเวอร์โฟลว์และอื่น ๆ เพื่อความง่าย)ตัวนับความปลอดภัยของเธรดจะทำงานตามกฎเหล่านั้นโดยไม่คำนึงถึงจำนวนเธรดที่เข้าถึงพร้อมกัน
หมายเหตุ: cross-post บนโปรแกรมเมอร์
เพียง - รหัสจะทำงานได้ดีถ้ามีหลายเธรดที่กำลังเรียกใช้รหัสนี้ในเวลาเดียวกัน
อย่าสับสนกับความปลอดภัยของเธรดด้วยการกำหนด โค้ดที่ปลอดภัยสำหรับเธรดสามารถเป็นแบบไม่กำหนดค่าได้ เมื่อพิจารณาถึงความยากในการแก้ไขปัญหาที่เกิดขึ้นกับโค้ดที่เป็นเธรดนี่อาจเป็นกรณีปกติ :-)
ความปลอดภัยของเธรดช่วยให้มั่นใจได้ว่าเมื่อเธรดกำลังแก้ไขหรืออ่านข้อมูลที่แชร์ไม่มีเธรดอื่นใดที่สามารถเข้าถึงเธรดในวิธีที่เปลี่ยนแปลงข้อมูล หากรหัสของคุณขึ้นอยู่กับคำสั่งบางอย่างสำหรับการดำเนินการเพื่อความถูกต้องคุณต้องใช้กลไกการซิงโครไนซ์อื่น ๆ นอกเหนือจากที่จำเป็นสำหรับความปลอดภัยของเธรดเพื่อให้แน่ใจในสิ่งนี้
ฉันต้องการเพิ่มข้อมูลเพิ่มเติมที่ด้านบนของคำตอบที่ดีอื่น ๆ
ความปลอดภัยของเธรดหมายถึงหลายเธรดสามารถเขียน / อ่านข้อมูลในวัตถุเดียวกันโดยไม่มีข้อผิดพลาดหน่วยความจำไม่สอดคล้องกัน ในโปรแกรมหลายเธรดสูงซึ่งเป็นโปรแกรมที่ปลอดภัยด้ายไม่ก่อให้เกิดผลข้างเคียงกับข้อมูลที่ใช้ร่วมกัน
ดูคำถาม SE นี้สำหรับรายละเอียดเพิ่มเติม:
โปรแกรมความปลอดภัยด้ายรับประกันความสอดคล้องหน่วยความจำ
จากหน้าเอกสารของ Oracle ใน API พร้อมกันขั้นสูง:
คุณสมบัติความสอดคล้องของหน่วยความจำ:
บทที่ 17 ของข้อกำหนดภาษา Java ™กำหนดความสัมพันธ์ที่เกิดขึ้นก่อนการดำเนินงานหน่วยความจำเช่นการอ่านและเขียนของตัวแปรที่ใช้ร่วมกัน ผลลัพธ์ของการเขียนโดยหนึ่งกระทู้รับประกันว่าจะสามารถอ่านได้โดยเธรดอื่นเฉพาะเมื่อการเขียนเกิดขึ้นก่อนการดำเนินการอ่านผลที่ได้จากการเขียนโดยหนึ่งในหัวข้อที่มีการรับประกันที่จะมองเห็นการอ่านโดยด้ายเฉพาะในกรณีที่การดำเนินการเขียนเกิดขึ้นก่อนที่จะดำเนินการอ่านอีก
synchronized
และvolatile
โครงสร้างเช่นเดียวกับThread.start()
และThread.join()
วิธีการรูปแบบที่สามารถเกิดขึ้นมาก่อนความสัมพันธ์
วิธีการของการเรียนทั้งหมดในjava.util.concurrent
และแพคเกจย่อยของมันขยายการรับประกันเหล่านี้เพื่อการประสานในระดับที่สูงขึ้น โดยเฉพาะอย่างยิ่ง:
Runnable
ไปยังExecutor
เกิดขึ้นก่อนที่การดำเนินการจะเริ่มต้นขึ้น ในทำนองเดียวกันสำหรับ Callables ExecutorService
ส่งต่อไปยังFuture
กระทำที่เกิดขึ้นก่อนการดำเนินการหลังจากการดึงผลลัพธ์ผ่านทางFuture.get()
ในเธรดอื่นLock.unlock, Semaphore.release, and CountDownLatch.countDown
เกิดขึ้นก่อนการกระทำที่ตามมาด้วยวิธี "การรับ" ที่ประสบความสำเร็จเช่นLock.lock, Semaphore.acquire, Condition.await, and CountDownLatch.await
บนวัตถุซิงโครไนซ์เดียวกันในเธรดอื่นExchanger
กระทำก่อนหน้าexchange()
ในแต่ละเธรดจะเกิดขึ้นก่อนที่จะเกิดขึ้นภายหลังจากการแลกเปลี่ยนที่สอดคล้องกัน () ในเธรดอื่นCyclicBarrier.await
และPhaser.awaitAdvance
(รวมถึงตัวแปร) เกิดขึ้นก่อนที่การกระทำที่ดำเนินการโดยสิ่งกีดขวางและการกระทำที่ดำเนินการโดยการกระทำสิ่งกีดขวางที่เกิดขึ้น - ก่อนการกระทำหลังจากการกลับมาประสบความสำเร็จจากหากต้องการคำตอบอื่น ๆ ให้สมบูรณ์:
การซิงโครไนซ์เป็นเรื่องที่กังวลเมื่อโค้ดในวิธีการของคุณทำหนึ่งในสองสิ่งต่อไปนี้:
ซึ่งหมายความว่าตัวแปรที่กำหนดไว้ในวิธีการของคุณจะปลอดภัยเสมอ การเรียกใช้เมธอดทุกครั้งจะมีตัวแปรเหล่านี้ในเวอร์ชันของตนเอง ถ้าเมธอดนั้นถูกเรียกโดยเธรดอื่นหรือโดยเธรดเดียวกันหรือแม้ว่าเมธอดจะเรียกตัวเอง (เรียกซ้ำ) ค่าของตัวแปรเหล่านี้จะไม่ถูกแชร์
การตั้งเวลากระทู้ไม่ได้รับประกันว่าจะไปเรื่อย งานทั้งหมดอาจทำให้ CPU เสียค่าใช้จ่ายของเธรดที่มีลำดับความสำคัญเท่ากัน คุณสามารถใช้ Thread.yield () เพื่อมีมโนธรรม คุณสามารถใช้ (ใน java) Thread.setPriority (Thread.NORM_PRIORITY-1) เพื่อลดลำดับความสำคัญของเธรด
บวกกับระวัง:
ใช่และใช่ แสดงว่าข้อมูลไม่ถูกแก้ไขโดยเธรดมากกว่าหนึ่งเธรดพร้อมกัน อย่างไรก็ตามโปรแกรมของคุณอาจทำงานได้ตามที่คาดหวังและปรากฏว่ามีความปลอดภัยในการใช้งานแม้ว่าจะไม่ได้อยู่ในระดับพื้นฐานก็ตาม
โปรดทราบว่าผลลัพธ์ที่คาดการณ์ไม่ได้เป็นผลมาจาก 'เงื่อนไขการแข่งขัน' ซึ่งอาจส่งผลให้ข้อมูลถูกปรับเปลี่ยนในลำดับอื่นนอกเหนือจากที่คาดไว้
ลองตอบคำถามนี้ตามตัวอย่าง:
class NonThreadSafe {
private int counter = 0;
public boolean countTo10() {
count = count + 1;
return (count == 10);
}
countTo10
วิธีการหนึ่งที่จะเพิ่มเคาน์เตอร์และจากนั้นส่งกลับจริงถ้านับได้ถึง 10 มันควรกลับมาครั้งเดียวจริง
วิธีนี้จะใช้ได้ตราบใดที่มีเพียงเธรดเดียวเท่านั้นที่กำลังเรียกใช้รหัส หากเธรดสองตัวรันรหัสในเวลาเดียวกันอาจเกิดปัญหาต่าง ๆ ได้
ตัวอย่างเช่นหากการนับเริ่มต้นที่ 9 หนึ่งเธรดสามารถเพิ่ม 1 ถึงนับ (ทำ 10) แต่จากนั้นเธรดที่สองสามารถเข้าสู่วิธีการและเพิ่ม 1 อีกครั้ง (ทำ 11) ก่อนที่เธรดแรกจะมีโอกาสดำเนินการเปรียบเทียบกับ 10 จากนั้นทั้งสองเธรดจะทำการเปรียบเทียบและพบว่าจำนวนนั้นเป็น 11 และไม่ส่งคืนค่าจริง
ดังนั้นรหัสนี้ไม่ปลอดภัยเธรด
ในสาระสำคัญปัญหามัลติเธรดทั้งหมดเกิดจากการเปลี่ยนแปลงของปัญหาชนิดนี้
วิธีแก้ไขคือเพื่อให้แน่ใจว่าการเพิ่มและการเปรียบเทียบไม่สามารถแยกออกได้ (ตัวอย่างเช่นโดยการล้อมรอบคำสั่งทั้งสองด้วยรหัสการซิงโครไนซ์บางชนิด) หรือโดยการหาวิธีแก้ปัญหาที่ไม่ต้องการการดำเนินการสองอย่าง รหัสดังกล่าวจะปลอดภัยต่อเธรด
อย่างน้อยใน C ++ ฉันคิดว่าthread-safeเป็นบิตของการเรียกชื่อผิดที่มันทำให้ชื่อออกมาเยอะมาก เพื่อความปลอดภัยของเธรดรหัสโดยทั่วไปจะต้องมีการดำเนินการเชิงรุกเกี่ยวกับเรื่องนี้ โดยทั่วไปจะไม่ได้คุณภาพแฝง
เพื่อให้ชั้นเรียนมีความปลอดภัยกับดอกยางจะต้องมีคุณสมบัติ "พิเศษ" ที่เพิ่มค่าใช้จ่าย คุณสมบัติเหล่านี้เป็นส่วนหนึ่งของการนำคลาสไปใช้และโดยทั่วไปแล้วจะซ่อนอยู่ในส่วนต่อประสาน นั่นคือกระทู้ที่แตกต่างกันสามารถเข้าถึงสมาชิกของชั้นเรียนโดยไม่ต้องกังวลเกี่ยวกับความขัดแย้งกับการเข้าถึงพร้อมกันโดยเธรดที่แตกต่างกันและสามารถทำได้ในลักษณะที่ขี้เกียจมากโดยใช้รูปแบบการเขียนรหัสปกติธรรมดาของมนุษย์ธรรมดาโดยไม่ต้องทำ ทุกสิ่งที่ซิงโครไนซ์แบบบ้าคลั่งที่มีอยู่แล้วในความกล้าของรหัสที่ถูกเรียก
และนี่คือเหตุผลที่บางคนชอบที่จะใช้คำว่าตรงกันภายใน
มีคำศัพท์หลักสามชุดสำหรับแนวคิดเหล่านี้ที่ฉันได้พบ ครั้งแรกและเป็นที่นิยมในอดีต (แต่แย่กว่า) คือ:
ที่สอง (และดีกว่า) คือ:
ที่สามคือ:
เธรดปลอดภัย ~ พิสูจน์เธรด ~ ซิงโครไนซ์ภายใน
ตัวอย่างของระบบซิงโครไนซ์ภายใน (aka. ความปลอดภัยของเธรดหรือการพิสูจน์เธรด ) เป็นร้านอาหารที่โฮสต์ต้อนรับคุณที่ประตูและไม่อนุญาตให้คุณเข้าคิว โฮสต์เป็นส่วนหนึ่งของกลไกของร้านอาหารในการจัดการกับลูกค้าหลายรายและสามารถใช้กลเม็ดที่ค่อนข้างยุ่งยากในการเพิ่มประสิทธิภาพการนั่งของลูกค้าที่รอคอยเช่นการพิจารณาขนาดของปาร์ตี้ของพวกเขาหรือเวลาเท่าที่พวกเขามี หรือแม้กระทั่งทำการจองทางโทรศัพท์ ร้านอาหารมีการซิงโครไนซ์ภายในเนื่องจากทั้งหมดนี้เป็นส่วนหนึ่งของอินเทอร์เฟซสำหรับการโต้ตอบกับมัน
ไม่ปลอดภัยสำหรับเธรด (แต่ดี) เข้ากันได้กับเธรด ~ ซิงโครไนซ์ภายนอก ~ ฟรีเธรด
สมมติว่าคุณไปธนาคาร มีเส้นคือการต่อสู้เพื่อพนักงานธนาคาร เนื่องจากคุณไม่ใช่คนป่าเถื่อนคุณจึงตระหนักว่าสิ่งที่ดีที่สุดที่ต้องทำในการต่อสู้เพื่อทรัพยากรคือการเข้าคิวเหมือนสิ่งมีชีวิตที่มีอารยธรรม ไม่มีใครทำให้คุณทำในทางเทคนิค เราหวังว่าคุณจะมีโปรแกรมทางสังคมที่จำเป็นในการทำด้วยตัวเอง ในแง่นี้ล็อบบี้ของธนาคารจะถูกซิงโครไนซ์จากภายนอก เราควรจะพูดว่ามันไม่ปลอดภัยหรือไม่ นั่นคือสิ่งที่หมายคือถ้าคุณไปกับด้ายปลอดภัย , ด้ายปลอดภัยชุดคำศัพท์สองขั้ว มันไม่ใช่ชุดคำศัพท์ที่ดีมาก คำศัพท์ที่ดีกว่าจะถูกซิงโครไนซ์จากภายนอกล็อบบี้ธนาคารไม่ได้เป็นมิตรกับลูกค้าหลายราย แต่มันก็ไม่ได้ทำการซิงโครไนซ์ ลูกค้าทำเอง
สิ่งนี้เรียกอีกอย่างว่า "free threaded" โดยที่ "free" อยู่ใน "free lice" - หรือในกรณีนี้คือ lock การซิงโครไนซ์แบบดั้งเดิมถูกต้องแม่นยำยิ่งขึ้น แต่นั่นไม่ได้หมายความว่ารหัสสามารถทำงานได้หลายเธรดโดยไม่ต้องมีรหัสดั้งเดิม มันหมายความว่ามันไม่ได้มาพร้อมกับพวกเขาติดตั้งแล้วและมันก็ขึ้นอยู่กับคุณผู้ใช้รหัสเพื่อติดตั้งด้วยตัวเอง แต่คุณเห็นว่าเหมาะสม การติดตั้งการซิงโครไนซ์แบบดั้งเดิมของคุณเองอาจเป็นเรื่องยากและต้องใช้ความคิดอย่างหนักเกี่ยวกับโค้ด แต่ยังสามารถนำไปสู่โปรแกรมที่เร็วที่สุดที่เป็นไปได้ด้วยการอนุญาตให้คุณกำหนดวิธีที่โปรแกรม
เธรดไม่ปลอดภัย (และไม่ดี) ~ เธรดที่เป็นมิตร ~ ไม่ซิงโครไนซ์
ตัวอย่างการใช้ชีวิตประจำวันของระบบthread-hostileคือการกระตุกด้วยรถสปอร์ตปฏิเสธที่จะใช้ไฟกระพริบและเปลี่ยนเลนโดยจำใจ สไตล์การขับขี่ของพวกเขาคือด้ายที่ไม่เป็นมิตรหรือไม่สามารถปรับแต่งได้เพราะคุณไม่มีวิธีที่จะประสานงานกับพวกเขาและสิ่งนี้สามารถนำไปสู่การแย่งชิงในเลนเดียวกันโดยไม่มีการแก้ไขและทำให้เกิดอุบัติเหตุเป็นรถสองคัน ป้องกันสิ่งนี้ รูปแบบนี้สามารถคิดได้กว้างกว่าการต่อต้านสังคมซึ่งฉันชอบเพราะมันมีความเฉพาะเจาะจงกับเธรดน้อยกว่าและโดยทั่วไปจะใช้กับการเขียนโปรแกรมหลายด้าน
เป็นครั้งแรกและเก่าแก่ที่สุดของชุดคำศัพท์ล้มเหลวที่จะทำให้ความแตกต่างระหว่างปลีกย่อยเป็นศัตรูด้ายและการทำงานร่วมกันด้าย ความเข้ากันได้ของเธรดนั้นแฝงมากกว่าความปลอดภัยของเธรดที่เรียกว่า แต่นั่นไม่ได้หมายความว่ารหัสที่เรียกนั้นไม่ปลอดภัยสำหรับการใช้เธรดพร้อมกัน มันหมายถึงว่ามันแฝงอยู่กับการซิงโครไนซ์ที่จะอนุญาตให้วางมันลงในรหัสการโทรแทนที่จะให้มันเป็นส่วนหนึ่งของการใช้งานภายใน ความเข้ากันได้ของเธรดคือการเขียนโค้ดโดยค่าเริ่มต้นในกรณีส่วนใหญ่ แต่นี่ก็เป็นเรื่องที่น่าเศร้าที่คิดว่าเป็นเธรดที่ไม่ปลอดภัยราวกับว่ามันป้องกันความปลอดภัยโดยเนื้อแท้ซึ่งเป็นจุดสำคัญของความสับสนสำหรับโปรแกรมเมอร์
หมายเหตุ: คู่มือซอฟต์แวร์จำนวนมากใช้คำว่า "thread-safe" จริง ๆ เพื่ออ้างถึง "thread-compatible" เพื่อเพิ่มความสับสนให้กับสิ่งที่เป็นระเบียบอยู่แล้ว! ฉันหลีกเลี่ยงคำว่า "thread-safe" และ "thread-unsafe" ด้วยเหตุผลทั้งหมดนี้เนื่องจากบางแหล่งจะเรียกบางอย่าง "thread-safe" ในขณะที่คนอื่น ๆ จะเรียกมันว่า "thread-unsafe" เพราะพวกเขาไม่เห็นด้วย ไม่ว่าคุณจะต้องทำตามมาตรฐานพิเศษเพื่อความปลอดภัย (การซิงโครไนซ์ดั้งเดิม) หรือไม่เป็นศัตรูที่จะถือว่า "ปลอดภัย" ดังนั้นหลีกเลี่ยงข้อกำหนดเหล่านั้นและใช้ข้อกำหนดที่ชาญฉลาดแทนเพื่อหลีกเลี่ยงการสื่อสารที่เป็นอันตรายกับวิศวกรรายอื่น
เป้าหมายหลักของเราคือทำลายความโกลาหล
เราทำเช่นนั้นโดยการสร้างระบบกำหนดขึ้นมาที่เราสามารถพึ่งพาได้ การกำหนดราคาแพงส่วนใหญ่เกิดจากค่าเสียโอกาสของการสูญเสียความเท่าเทียม, การวางท่อและการเรียงลำดับใหม่ เราพยายามที่จะลดจำนวนการกำหนดระดับที่เราต้องทำให้ต้นทุนของเราต่ำในขณะที่ยังหลีกเลี่ยงการตัดสินใจที่จะกัดกร่อนระดับที่เราสามารถหาได้
การซิงโครไนซ์ของเธรดเป็นเรื่องเกี่ยวกับการเพิ่มลำดับและลดความสับสนวุ่นวาย ระดับที่คุณทำเช่นนี้สอดคล้องกับข้อกำหนดที่กล่าวถึงข้างต้น ระดับสูงสุดหมายถึงระบบทำงานในลักษณะที่คาดการณ์ได้อย่างสมบูรณ์ทุกครั้ง ระดับที่สองหมายความว่าระบบทำงานได้ดีพอที่รหัสการโทรสามารถตรวจสอบความไม่แน่นอนได้อย่างน่าเชื่อถือ ยกตัวอย่างเช่นการปลอมปลุกในตัวแปรสภาพหรือความล้มเหลวเพื่อล็อค mutex เพราะยังไม่พร้อม ระดับที่สามหมายถึงระบบไม่ทำงานได้ดีพอที่จะเล่นกับคนอื่นและสามารถเล่นได้แบบเธรดเดียวโดยไม่เกิดความโกลาหล
แทนที่จะคิดว่าโค้ดหรือคลาสเป็นเธรดที่ปลอดภัยหรือไม่ฉันคิดว่าการคิดว่าการกระทำนั้นปลอดภัยกว่าการใช้เธรด การกระทำสองอย่างนั้นปลอดภัยสำหรับเธรดหากพวกเขาจะทำงานตามที่ระบุไว้เมื่อเรียกใช้จากบริบทเธรดโดยพลการ ในหลายกรณีคลาสจะสนับสนุนการผสมผสานบางอย่างของการกระทำในลักษณะที่ปลอดภัยต่อเธรดและอื่น ๆ ที่ไม่ใช่
ตัวอย่างเช่นคอลเลกชันจำนวนมากเช่นรายการอาร์เรย์และชุดแฮชจะรับประกันได้ว่าหากพวกเขามีการเข้าถึง แต่เพียงผู้เดียวในตอนแรกและพวกเขาไม่เคยแก้ไขหลังจากการอ้างอิงจะปรากฏให้เห็นกระทู้อื่น ๆ พวกเขาอาจถูกอ่านโดยรวม ของหัวข้อโดยไม่มีการรบกวน
ที่น่าสนใจคือชุดของชุดแฮชบางชุดเช่นชุดที่ไม่ใช่แบบทั่วไปใน. NET อาจรับประกันได้ว่าตราบใดที่ไม่มีรายการใดถูกลบออกไปและหากว่ามีเพียงหนึ่งเธรดเท่านั้นที่เคยเขียนลงไป อ่านคอลเลกชันจะทำตัวราวกับว่ากำลังเข้าถึงคอลเลกชันที่การอัปเดตอาจล่าช้าและเกิดขึ้นตามลำดับโดยพลการ แต่จะดำเนินการตามปกติ หากเธรด # 1 เพิ่ม X จากนั้น Y และเธรด # 2 ค้นหาและเห็น Y และ X แล้วอาจเป็นไปได้ที่เธรด # 2 จะเห็นว่า Y มีอยู่ แต่ X ไม่ได้ พฤติกรรมดังกล่าวจะเป็น "thread-safe" หรือไม่นั้นขึ้นอยู่กับว่า thread # 2 พร้อมที่จะจัดการกับความเป็นไปได้นั้นหรือไม่
หมายเหตุสุดท้ายบางคลาส - โดยเฉพาะการบล็อกไลบรารีการสื่อสาร - อาจมีวิธี "ปิด" หรือ "กำจัด" ซึ่งเป็นเธรดที่ปลอดภัยสำหรับวิธีการอื่น ๆ ทั้งหมด แต่ไม่มีวิธีอื่นใดที่ปลอดภัยต่อเธรดสำหรับ ซึ่งกันและกัน หากเธรดทำการร้องขอการบล็อกการอ่านและผู้ใช้ของโปรแกรมคลิกที่ "ยกเลิก" จะไม่มีวิธีใดที่การร้องขอปิดจะถูกส่งโดยเธรดที่พยายามทำการอ่าน อย่างไรก็ตามคำขอปิด / กำจัดอาจตั้งค่าสถานะแบบอะซิงโครนัสซึ่งจะทำให้การร้องขอการอ่านถูกยกเลิกโดยเร็วที่สุด เมื่อทำการปิดในเธรดใด ๆ วัตถุก็จะไร้ประโยชน์และความพยายามทั้งหมดที่การกระทำในอนาคตจะล้มเหลวทันที
ด้วยคำที่ง่ายที่สุด: P หากมีความปลอดภัยในการรันหลายเธรดบนบล็อกของรหัสมันจะปลอดภัยเธรด *
* เป็นไปตามเงื่อนไข
เงื่อนไขที่กล่าวถึงโดยคำตอบอื่น ๆ เช่น 1 ผลลัพธ์ควรเหมือนกันถ้าคุณรันหนึ่งเธรดหรือหลายเธรด