ที่ไม่ได้อีกจริงๆentrancy ; คุณไม่ได้เรียกใช้ฟังก์ชันสองครั้งในชุดข้อความเดียวกัน (หรือในชุดข้อความอื่น) คุณสามารถรับได้ผ่านการเรียกซ้ำหรือส่งผ่านที่อยู่ของฟังก์ชั่นปัจจุบันเป็นฟังก์ชั่นการเรียกกลับตัวชี้ไปยังฟังก์ชั่นอื่น (และมันจะไม่ปลอดภัยเพราะมันจะซิงโครนัส)
นี่เป็นเพียงธรรมดาวานิลลาข้อมูลการแข่งขัน UB (พฤติกรรมที่ไม่ได้กำหนด) ระหว่างจัดการสัญญาณและหัวข้อหลัก: เพียงsig_atomic_t
มีการประกันความปลอดภัยสำหรับการนี้ คนอื่นอาจทำงานเช่นในกรณีของคุณที่สามารถโหลดวัตถุ 8 ไบต์หรือเก็บไว้ด้วยคำสั่งเดียวใน x86-64 และคอมไพเลอร์เกิดขึ้นเพื่อเลือก asm (ตามคำตอบของ @ icarus แสดงให้เห็น)
ดูการเขียนโปรแกรม MCU - การเพิ่มประสิทธิภาพ C ++ O2 จะหยุดลงในขณะที่ลูป - ตัวจัดการขัดจังหวะบนไมโครคอนโทรลเลอร์แบบแกนเดียวนั้นเป็นสิ่งเดียวกับตัวจัดการสัญญาณในโปรแกรมเธรดเดี่ยว ในกรณีนั้นผลลัพธ์ของ UB คือโหลดถูกยกออกจากลูป
กรณีทดสอบของคุณจากการฉีกขาดเกิดขึ้นจริงเนื่องจาก UB ของ data-race อาจถูกพัฒนา / ทดสอบในโหมด 32 บิตหรือคอมไพเลอร์โง่กว่ารุ่นเก่าที่โหลดสมาชิก struct แยกต่างหาก
ในกรณีของคุณคอมไพเลอร์สามารถเพิ่มประสิทธิภาพร้านค้าออกจากวงวนไม่สิ้นสุดเนื่องจากไม่มีโปรแกรมฟรี UB ที่สามารถสังเกตได้ data
ไม่ใช่_Atomic
หรือvolatile
และไม่มีผลข้างเคียงอื่นในลูป ดังนั้นจึงไม่มีวิธีที่ผู้อ่านสามารถซิงโครไนซ์กับผู้เขียนคนนี้ ในความเป็นจริงนี้เกิดขึ้นหากคุณคอมไพล์ด้วยการเปิดใช้งานการเพิ่มประสิทธิภาพ ( Godboltแสดงการวนซ้ำที่ด้านล่างของหลัก) ฉันยังเปลี่ยน struct เป็นสองlong long
และ gcc ใช้movdqa
16-byte store เดียวก่อน loop (สิ่งนี้ไม่ได้รับประกันว่าเป็นอะตอมมิก แต่มันใช้กับซีพียูเกือบทั้งหมดโดยถือว่าอยู่ในแนวเดียวกันหรือใน Intel เพียง แต่ไม่ข้ามขอบเขตแคช - ไลน์ เหตุใดการกำหนดค่าจำนวนเต็มบนตัวแปรอะตอมมิกที่จัดเรียงตามธรรมชาติบน x86 )
ดังนั้นการรวบรวมด้วยการเปิดใช้งานการเพิ่มประสิทธิภาพจะทำให้การทดสอบของคุณหยุดชะงักและแสดงค่าเดิมทุกครั้ง C ไม่ใช่ภาษาแอสเซมบลีแบบพกพา
volatile struct two_int
ก็จะบังคับให้คอมไพเลอร์ไม่ปรับพวกเขาออกไป แต่จะไม่บังคับให้โหลด / เก็บโครงสร้างทั้งหมดของอะตอม (มันจะไม่หยุดมันจากการทำเช่นนั้นทั้งสองแม้ว่า.) หมายเหตุที่volatile
ไม่ได้หลีกเลี่ยงข้อมูลการแข่งขัน UB แต่ในทางปฏิบัติก็เพียงพอสำหรับการสื่อสารระหว่างด้ายและเป็นวิธีการที่คนสร้างขึ้น Atomics มือรีด (พร้อมกับ asm อินไลน์) ก่อน C11 / C ++ 11 สำหรับสถาปัตยกรรมซีพียูปกติ พวกเขากำลังแคชเชื่อมโยงกันเพื่อให้volatile
เป็นในทางปฏิบัติส่วนใหญ่คล้ายกับ_Atomic
ที่มีmemory_order_relaxed
สำหรับบริสุทธิ์โหลดและบริสุทธิ์ร้านถ้าใช้สำหรับประเภทแคบพอที่คอมไพเลอร์จะใช้คำสั่งเดียวเพื่อให้คุณไม่ได้รับการฉีกขาด และแน่นอนว่าvolatile
ไม่มีการรับประกันใด ๆ จากมาตรฐาน ISO C เทียบกับการเขียนโค้ดที่คอมไพล์กับ asm เดียวกันโดยใช้_Atomic
และ mo_relaxed
หากคุณมีฟังก์ชั่นที่ทำglobal_var++;
บนint
หรือlong long
ที่คุณเรียกใช้จากหลักและแบบอะซิงโครนัสจากตัวจัดการสัญญาณนั่นจะเป็นวิธีที่จะใช้การป้อนข้อมูลใหม่เพื่อสร้าง UB ของ data-race
ขึ้นอยู่กับว่ามันรวบรวม (ไปยังหน่วยความจำปลายทาง inc หรือเพิ่มหรือแยกโหลด / inc / store) มันจะเป็นอะตอมหรือไม่เกี่ยวกับตัวจัดการสัญญาณในหัวข้อเดียวกัน ดูที่num ++ สามารถเป็นอะตอมสำหรับ 'int NUM' สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ atomicity บน x86 และใน C ++ (C11's stdatomic.h
และ_Atomic
คุณลักษณะให้ฟังก์ชันที่เทียบเท่ากับstd::atomic<T>
แม่แบบของ C ++ 11 )
ข้อขัดจังหวะหรือข้อยกเว้นอื่น ๆ ไม่สามารถเกิดขึ้นได้ในระหว่างการเรียนการสอนดังนั้นการเพิ่มหน่วยความจำปลายทางจึงเป็นอะตอมมิก wrt context switch บน CPU แบบ single-core ตัวเขียน DMA (ที่สอดคล้องกัน) เท่านั้นที่สามารถ "เพิ่ม" การเพิ่มขึ้นจากการadd [mem], 1
ไม่มีlock
คำนำหน้าบน CPU แบบคอร์เดียว ไม่มีคอร์อื่นใดที่เธรดอื่นสามารถทำงานได้
ดังนั้นจึงคล้ายกับกรณีของสัญญาณ: ตัวจัดการสัญญาณทำงานแทนการดำเนินการตามปกติของเธรดที่จัดการสัญญาณดังนั้นจึงไม่สามารถจัดการได้ในช่วงกลางของคำสั่งเดียว