ความแตกต่างระหว่าง atomic และ Critical ใน OpenMP คืออะไร?
ฉันสามารถทำได้
#pragma omp atomic
g_qCount++;
แต่ไม่เหมือนกับ
#pragma omp critical
g_qCount++;
เหรอ?
ความแตกต่างระหว่าง atomic และ Critical ใน OpenMP คืออะไร?
ฉันสามารถทำได้
#pragma omp atomic
g_qCount++;
แต่ไม่เหมือนกับ
#pragma omp critical
g_qCount++;
เหรอ?
คำตอบ:
ผลกระทบต่อ g_qCount เหมือนกัน แต่สิ่งที่ทำนั้นแตกต่างกัน
ส่วนที่สำคัญของ OpenMP นั้นเป็นเรื่องทั่วไปโดยสิ้นเชิง - สามารถล้อมรอบบล็อกโค้ดใดก็ได้ อย่างไรก็ตามคุณต้องจ่ายเงินสำหรับค่าใช้จ่ายทั่วไปนั้นโดยทำให้เกิดค่าโสหุ้ยที่สำคัญทุกครั้งที่เธรดเข้าและออกจากส่วนวิกฤต (ด้านบนของค่าใช้จ่ายในการทำให้เป็นอนุกรม)
(นอกจากนี้ใน OpenMP ส่วนวิกฤตที่ไม่มีชื่อทั้งหมดจะถือว่าเหมือนกัน (หากคุณต้องการจะมีการล็อกเพียงครั้งเดียวสำหรับส่วนวิกฤตที่ไม่มีชื่อทั้งหมด) ดังนั้นหากเธรดหนึ่งเธรดอยู่ในส่วนวิกฤต [ไม่มีชื่อ] หนึ่งหัวข้อดังข้างต้นจะไม่มีเธรดใดสามารถป้อนได้ [ไม่มีชื่อ] ส่วนที่สำคัญอย่างที่คุณคาดเดาคุณสามารถแก้ไขปัญหานี้ได้โดยใช้ส่วนวิกฤตที่ตั้งชื่อ)
การทำงานของอะตอมมีค่าใช้จ่ายที่ต่ำกว่ามาก หากมีให้ใช้ประโยชน์จากฮาร์ดแวร์ที่ให้ (พูด) การดำเนินการเพิ่มอะตอม ในกรณีนั้นไม่จำเป็นต้องล็อก / ปลดล็อกในการป้อน / ออกจากบรรทัดของรหัสเพียงแค่เพิ่มการเพิ่มขึ้นของอะตอมซึ่งฮาร์ดแวร์บอกว่าคุณไม่สามารถแทรกแซงได้
ข้อดีก็คือค่าโสหุ้ยนั้นต่ำกว่ามากและเธรดหนึ่งที่อยู่ในการดำเนินการของอะตอมไม่ได้ปิดกั้นการดำเนินการของอะตอม (อื่น ๆ ) ที่กำลังจะเกิดขึ้น ข้อเสียคือชุดปฏิบัติการที่ จำกัด ซึ่งอะตอมรองรับ
แน่นอนไม่ว่าในกรณีใดคุณต้องเสียค่าใช้จ่ายในการทำให้เป็นอนุกรม
ใน OpenMP ส่วนวิกฤตที่ไม่มีชื่อทั้งหมดจะไม่สามารถใช้ร่วมกันได้
ความแตกต่างที่สำคัญที่สุดระหว่างคริติคอลและอะตอมคืออะตอมสามารถป้องกันการกำหนดเพียงงานเดียวและคุณสามารถใช้กับตัวดำเนินการเฉพาะได้
ส่วนที่สำคัญ:
สามารถขยายไปยังกลุ่มบล็อกที่ต่อเนื่องกันได้โดยใช้แท็ก "name" อย่างเหมาะสม
ช้ากว่า!
การทำงานของอะตอม:
เร็วกว่ามาก!
ทำให้มั่นใจได้เฉพาะการทำให้เป็นอนุกรมของการดำเนินการเฉพาะ
วิธีที่เร็วที่สุดไม่ใช่ทั้งวิกฤตหรือปรมาณู โดยประมาณการบวกด้วยส่วนวิกฤตมีราคาแพงกว่าการเพิ่มแบบธรรมดาถึง 200 เท่าการเพิ่มอะตอมมีราคาแพงกว่าการเติมแบบธรรมดาถึง 25 เท่า
ตัวเลือกที่เร็วที่สุด (ไม่สามารถใช้ได้เสมอไป) คือให้แต่ละเธรดของตัวนับเป็นของตัวเองและทำการลดเมื่อคุณต้องการผลรวมทั้งหมด
ข้อ จำกัด ของatomic
มีความสำคัญ พวกเขาควรจะมีรายละเอียดเกี่ยวกับรายละเอียด OpenMP MSDNเสนอสูตรโกงด่วนเพราะฉันจะไม่แปลกใจถ้าสิ่งนี้จะไม่เปลี่ยนแปลง (Visual Studio 2012 มีการใช้งาน OpenMP ตั้งแต่เดือนมีนาคม 2545) หากต้องการอ้างอิง MSDN:
คำสั่งนิพจน์ต้องมีรูปแบบใดรูปแบบหนึ่งต่อไปนี้:
x
binop =expr
x++
++x
x--
--x
ในนิพจน์ก่อนหน้า:
x
เป็นlvalue
นิพจน์ที่มีประเภทสเกลาร์ คือการแสดงออกที่มีประเภทสเกลาร์และมันไม่ได้อ้างอิงวัตถุที่กำหนดโดยexpr
binopไม่ได้เป็นผู้ประกอบการมากเกินไปและเป็นหนึ่ง, , , , , , , หรือx
+
*
-
/
&
^
|
<<
>>
ขอแนะนำให้ใช้atomic
เมื่อคุณสามารถตั้งชื่อส่วนสำคัญเป็นอย่างอื่นได้ การตั้งชื่อเป็นสิ่งสำคัญ คุณจะหลีกเลี่ยงการแก้ไขอาการปวดหัวด้วยวิธีนี้
มีคำอธิบายที่ยอดเยี่ยมอยู่แล้วที่นี่ อย่างไรก็ตามเราสามารถดำน้ำลึกลงไปอีกเล็กน้อย เพื่อให้เข้าใจถึงความแตกต่างหลักระหว่างแนวคิดส่วนอะตอมและส่วนวิกฤตใน OpenMP เราต้องเข้าใจแนวคิดของการล็อกก่อน รีวิว Let 's เหตุผลที่เราจำเป็นต้องใช้ล็อค
โปรแกรมคู่ขนานกำลังดำเนินการโดยหลายเธรด ผลลัพธ์ที่กำหนดจะเกิดขึ้นก็ต่อเมื่อเราทำการซิงโครไนซ์ระหว่างเธรดเหล่านี้ แน่นอนว่าการซิงโครไนซ์ระหว่างเธรดไม่จำเป็นเสมอไป เราอ้างถึงกรณีเหล่านั้นว่าจำเป็นต้องมีการซิงโครไนซ์
เพื่อที่จะประสานหัวข้อในโปรแกรมแบบมัลติเธรดเราจะใช้ล็อค เมื่อจำเป็นต้อง จำกัด การเข้าถึงด้วยเธรดเดียวในแต่ละครั้งการล็อคจะเข้ามามีบทบาท ล็อคการดำเนินแนวคิดอาจแตกต่างจากการประมวลผลการประมวลผล มาดูกันว่าการล็อกแบบธรรมดาสามารถทำงานได้อย่างไรจากมุมมองของอัลกอริทึม
1. Define a variable called lock.
2. For each thread:
2.1. Read the lock.
2.2. If lock == 0, lock = 1 and goto 3 // Try to grab the lock
Else goto 2.1 // Wait until the lock is released
3. Do something...
4. lock = 0 // Release the lock
อัลกอริทึมที่กำหนดสามารถใช้งานได้ในภาษาฮาร์ดแวร์ดังนี้ เราจะสมมติว่าโปรเซสเซอร์ตัวเดียวและวิเคราะห์พฤติกรรมของการล็อคในนั้น สำหรับการปฏิบัตินี้สมมติหนึ่งในการประมวลผลต่อไปนี้: MIPS , อัลฟา , ARMหรือพาวเวอร์
try: LW R1, lock
BNEZ R1, try
ADDI R1, R1, #1
SW R1, lock
โปรแกรมนี้ดูเหมือนจะใช้ได้ แต่ไม่ใช่ รหัสข้างต้นทนทุกข์ทรมานจากปัญหาก่อนหน้านี้ การประสาน มาค้นหาปัญหากัน สมมติว่าค่าเริ่มต้นของการล็อกเป็นศูนย์ หากเธรดสองเธรดเรียกใช้รหัสนี้ตัวหนึ่งอาจไปถึงSW R1 ล็อกก่อนที่อีกอันจะอ่านตัวแปรล็อก ดังนั้นทั้งคู่จึงคิดว่าล็อคฟรี เพื่อแก้ปัญหานี้มีคำแนะนำอื่นที่ให้มาแทนที่จะเป็นLWและSW แบบธรรมดา เรียกว่าRead-Modify-Write instruction เป็นคำสั่งที่ซับซ้อน (ประกอบด้วยคำแนะนำย่อย) ซึ่งทำให้มั่นใจได้ว่าขั้นตอนการได้มาซึ่งการล็อคนั้นทำได้เพียงคำสั่งเดียวด้ายในแต่ละครั้ง ความแตกต่างของการอ่านปรับเปลี่ยน-เขียนเมื่อเทียบกับที่เรียบง่ายอ่านและเขียนคำแนะนำคือการใช้วิธีที่แตกต่างกันของการโหลดและการจัดเก็บ ใช้LL (Load Linked) เพื่อโหลดตัวแปรล็อคและSC (Store Conditional) เพื่อเขียนลงในตัวแปร lock การลงทะเบียนลิงค์เพิ่มเติมใช้เพื่อให้มั่นใจว่าขั้นตอนของการได้มาของการล็อคนั้นทำได้โดยเธรดเดียว อัลกอริทึมได้รับด้านล่าง
1. Define a variable called lock.
2. For each thread:
2.1. Read the lock and put the address of lock variable inside the Link Register.
2.2. If (lock == 0) and (&lock == Link Register), lock = 1 and reset the Link Register then goto 3 // Try to grab the lock
Else goto 2.1 // Wait until the lock is released
3. Do something...
4. lock = 0 // Release the lock
เมื่อรีจิสเตอร์ลิงก์ถูกรีเซ็ตหากเธรดอื่นถือว่าการล็อกเป็นอิสระเธรดจะไม่สามารถเขียนค่าที่เพิ่มขึ้นลงในล็อกได้อีก ดังนั้นจึงได้รับความพร้อมกันของการเข้าถึงตัวแปรล็อค
ความแตกต่างหลักระหว่างวิกฤตและอะตอมมาจากแนวคิดที่ว่า:
เหตุใดจึงต้องใช้การล็อก (ตัวแปรใหม่) ในขณะที่เราสามารถใช้ตัวแปรจริง (ซึ่งเรากำลังดำเนินการอยู่) เป็นตัวแปรล็อก
การใช้ตัวแปรใหม่สำหรับการล็อกจะนำไปสู่ส่วนวิกฤตในขณะที่การใช้ตัวแปรจริงเป็นตัวล็อกจะนำไปสู่แนวคิดเกี่ยวกับอะตอม ส่วนที่สำคัญมีประโยชน์เมื่อเราทำการคำนวณจำนวนมาก (มากกว่าหนึ่งบรรทัด) บนตัวแปรจริง นั่นเป็นเพราะหากไม่สามารถเขียนผลลัพธ์ของการคำนวณเหล่านั้นบนตัวแปรจริงได้ควรทำขั้นตอนทั้งหมดซ้ำเพื่อคำนวณผลลัพธ์ สิ่งนี้สามารถนำไปสู่ประสิทธิภาพที่ไม่ดีเมื่อเทียบกับการรอให้ปลดล็อกก่อนที่จะเข้าสู่ภูมิภาคที่มีการคำนวณสูง ดังนั้นขอแนะนำให้ใช้คำสั่งอะตอมเมื่อใดก็ตามที่คุณต้องการทำการคำนวณเดี่ยว (x ++, x--, ++ x, --x ฯลฯ ) และใช้คำสั่งที่สำคัญเมื่อภูมิภาคที่ซับซ้อนมากขึ้นกำลังดำเนินการโดยส่วนเร่งรัด
atomic ค่อนข้างมีประสิทธิภาพเมื่อคุณต้องการเปิดใช้งานการยกเว้นซึ่งกันและกันสำหรับคำสั่งเดียวที่คล้ายกันนั้นไม่เป็นความจริงเกี่ยวกับ omp Critical
atomic เป็นคำสั่งเดียวที่สำคัญคือคุณล็อคสำหรับการดำเนินการคำสั่งเดียว
ส่วนที่สำคัญคือการล็อคบล็อกของรหัส
คอมไพเลอร์ที่ดีจะแปลรหัสที่สองของคุณในลักษณะเดียวกับที่ทำในครั้งแรก
++
และ*=
) และถ้าพวกเขาจะไม่ได้รับการสนับสนุนในฮาร์ดแวร์ที่พวกเขาอาจจะถูกแทนที่โดยcritical
ส่วน