ความแตกต่างระหว่าง atomic และ Critical ใน OpenMP คืออะไร?


111

ความแตกต่างระหว่าง atomic และ Critical ใน OpenMP คืออะไร?

ฉันสามารถทำได้

#pragma omp atomic
g_qCount++;

แต่ไม่เหมือนกับ

#pragma omp critical
g_qCount++;

เหรอ?

คำตอบ:


174

ผลกระทบต่อ g_qCount เหมือนกัน แต่สิ่งที่ทำนั้นแตกต่างกัน

ส่วนที่สำคัญของ OpenMP นั้นเป็นเรื่องทั่วไปโดยสิ้นเชิง - สามารถล้อมรอบบล็อกโค้ดใดก็ได้ อย่างไรก็ตามคุณต้องจ่ายเงินสำหรับค่าใช้จ่ายทั่วไปนั้นโดยทำให้เกิดค่าโสหุ้ยที่สำคัญทุกครั้งที่เธรดเข้าและออกจากส่วนวิกฤต (ด้านบนของค่าใช้จ่ายในการทำให้เป็นอนุกรม)

(นอกจากนี้ใน OpenMP ส่วนวิกฤตที่ไม่มีชื่อทั้งหมดจะถือว่าเหมือนกัน (หากคุณต้องการจะมีการล็อกเพียงครั้งเดียวสำหรับส่วนวิกฤตที่ไม่มีชื่อทั้งหมด) ดังนั้นหากเธรดหนึ่งเธรดอยู่ในส่วนวิกฤต [ไม่มีชื่อ] หนึ่งหัวข้อดังข้างต้นจะไม่มีเธรดใดสามารถป้อนได้ [ไม่มีชื่อ] ส่วนที่สำคัญอย่างที่คุณคาดเดาคุณสามารถแก้ไขปัญหานี้ได้โดยใช้ส่วนวิกฤตที่ตั้งชื่อ)

การทำงานของอะตอมมีค่าใช้จ่ายที่ต่ำกว่ามาก หากมีให้ใช้ประโยชน์จากฮาร์ดแวร์ที่ให้ (พูด) การดำเนินการเพิ่มอะตอม ในกรณีนั้นไม่จำเป็นต้องล็อก / ปลดล็อกในการป้อน / ออกจากบรรทัดของรหัสเพียงแค่เพิ่มการเพิ่มขึ้นของอะตอมซึ่งฮาร์ดแวร์บอกว่าคุณไม่สามารถแทรกแซงได้

ข้อดีก็คือค่าโสหุ้ยนั้นต่ำกว่ามากและเธรดหนึ่งที่อยู่ในการดำเนินการของอะตอมไม่ได้ปิดกั้นการดำเนินการของอะตอม (อื่น ๆ ) ที่กำลังจะเกิดขึ้น ข้อเสียคือชุดปฏิบัติการที่ จำกัด ซึ่งอะตอมรองรับ

แน่นอนไม่ว่าในกรณีใดคุณต้องเสียค่าใช้จ่ายในการทำให้เป็นอนุกรม


5
"คุณสามารถพกพาไม่ได้" - ฉันไม่แน่ใจว่าเป็นความจริง มาตรฐาน (เวอร์ชั่น 2.0)ระบุว่าการดำเนินงานของอะตอมจะได้รับอนุญาต (โดยทั่วไปสิ่งที่ชอบ++และ*=) และถ้าพวกเขาจะไม่ได้รับการสนับสนุนในฮาร์ดแวร์ที่พวกเขาอาจจะถูกแทนที่โดยcriticalส่วน
Dan R

@ DanRoche: ใช่คุณพูดถูก ฉันไม่คิดว่าคำพูดนั้นจะถูกต้องฉันจะแก้ไขทันที
Jonathan Dursi

ไม่กี่วันที่ผ่านมาฉันติดตามบทช่วยสอน OpenMP และเท่าที่ฉันเข้าใจมีความแตกต่างในสองรหัสที่แตกต่างกัน นั่นคือผลลัพธ์อาจแตกต่างกันเนื่องจากส่วนที่สำคัญทำให้มั่นใจได้ว่าคำสั่งถูกดำเนินการโดยเธรดต่อครั้งอย่างไรก็ตามเป็นไปได้ว่าคำสั่ง: g_qCount = g_qCount + 1; สำหรับเธรด 1 เพียงแค่เก็บผลลัพธ์ g_qCount ไว้ใน writebuffer เท่านั้นที่ไม่ได้อยู่ในหน่วยความจำ RAM และเมื่อเธรด 2 ดึงค่า g_qCount มันก็เพียงแค่อ่านค่าใน RAM ไม่ใช่ใน writebuffer คำสั่งปรมาณูรับรองว่าคำสั่งจะล้างข้อมูลไปยังหน่วยความจำ
Giox79

31

ใน OpenMP ส่วนวิกฤตที่ไม่มีชื่อทั้งหมดจะไม่สามารถใช้ร่วมกันได้

ความแตกต่างที่สำคัญที่สุดระหว่างคริติคอลและอะตอมคืออะตอมสามารถป้องกันการกำหนดเพียงงานเดียวและคุณสามารถใช้กับตัวดำเนินการเฉพาะได้


13
นี่น่าจะเป็นการแสดงความคิดเห็น (หรือแก้ไข) ของคำตอบก่อนหน้านี้ดีกว่า
kynan

20

ส่วนที่สำคัญ:

  • ตรวจสอบการทำให้เป็นอนุกรมของบล็อกโค้ด
  • สามารถขยายไปยังกลุ่มบล็อกที่ต่อเนื่องกันได้โดยใช้แท็ก "name" อย่างเหมาะสม

  • ช้ากว่า!

การทำงานของอะตอม:

  • เร็วกว่ามาก!

  • ทำให้มั่นใจได้เฉพาะการทำให้เป็นอนุกรมของการดำเนินการเฉพาะ


9
แต่คำตอบนี้อ่านได้ง่ายมากและจะเป็นข้อสรุปที่ดีสำหรับคำตอบแรก
Michał Miszczyszyn

7

วิธีที่เร็วที่สุดไม่ใช่ทั้งวิกฤตหรือปรมาณู โดยประมาณการบวกด้วยส่วนวิกฤตมีราคาแพงกว่าการเพิ่มแบบธรรมดาถึง 200 เท่าการเพิ่มอะตอมมีราคาแพงกว่าการเติมแบบธรรมดาถึง 25 เท่า

ตัวเลือกที่เร็วที่สุด (ไม่สามารถใช้ได้เสมอไป) คือให้แต่ละเธรดของตัวนับเป็นของตัวเองและทำการลดเมื่อคุณต้องการผลรวมทั้งหมด


2
ฉันไม่เห็นด้วยกับตัวเลขทั้งหมดที่คุณพูดถึงในคำอธิบายของคุณ สมมติว่า x86_64 การดำเนินการของอะตอมจะมีค่าใช้จ่ายในวงจรสองสามรอบ (การซิงโครไนซ์บรรทัดแคช) ในราคาประมาณหนึ่งรอบ หากคุณมีค่าใช้จ่าย '' การแบ่งปันที่แท้จริง '' เป็นอย่างอื่นค่าโสหุ้ยก็เท่ากับ ส่วนที่สำคัญต้องเสียค่าใช้จ่ายในการล็อก ขึ้นอยู่กับว่ามีการล็อคอยู่แล้วหรือไม่ค่าใช้จ่ายเป็นค่าใช้จ่ายประมาณ 2 อะตอมหรือสองรันของตัวกำหนดตารางเวลาและเวลาสลีปซึ่งโดยปกติจะมากกว่า 200x อย่างมีนัยสำคัญ
Klaas van Gend

6

ข้อ จำกัด ของatomicมีความสำคัญ พวกเขาควรจะมีรายละเอียดเกี่ยวกับรายละเอียด OpenMP MSDNเสนอสูตรโกงด่วนเพราะฉันจะไม่แปลกใจถ้าสิ่งนี้จะไม่เปลี่ยนแปลง (Visual Studio 2012 มีการใช้งาน OpenMP ตั้งแต่เดือนมีนาคม 2545) หากต้องการอ้างอิง MSDN:

คำสั่งนิพจน์ต้องมีรูปแบบใดรูปแบบหนึ่งต่อไปนี้:

xbinop =expr

x++

++x

x--

--x

ในนิพจน์ก่อนหน้า: xเป็นlvalueนิพจน์ที่มีประเภทสเกลาร์ คือการแสดงออกที่มีประเภทสเกลาร์และมันไม่ได้อ้างอิงวัตถุที่กำหนดโดยexpr binopไม่ได้เป็นผู้ประกอบการมากเกินไปและเป็นหนึ่ง, , , , , , , หรือx+*-/&^|<<>>

ขอแนะนำให้ใช้atomicเมื่อคุณสามารถตั้งชื่อส่วนสำคัญเป็นอย่างอื่นได้ การตั้งชื่อเป็นสิ่งสำคัญ คุณจะหลีกเลี่ยงการแก้ไขอาการปวดหัวด้วยวิธีนี้


1
นี่ไม่ใช่ทั้งหมดเรามีคำสั่งเกี่ยวกับอะตอมขั้นสูงอื่น ๆ เช่น #pragma omp aromic update (หรืออ่านอัปเดตเขียนจับภาพ) ดังนั้นจึงช่วยให้เรามีคำชี้แจงที่เป็นประโยชน์อื่น ๆ
pooria

1

มีคำอธิบายที่ยอดเยี่ยมอยู่แล้วที่นี่ อย่างไรก็ตามเราสามารถดำน้ำลึกลงไปอีกเล็กน้อย เพื่อให้เข้าใจถึงความแตกต่างหลักระหว่างแนวคิดส่วนอะตอมและส่วนวิกฤตใน 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 ฯลฯ ) และใช้คำสั่งที่สำคัญเมื่อภูมิภาคที่ซับซ้อนมากขึ้นกำลังดำเนินการโดยส่วนเร่งรัด


-5

atomic ค่อนข้างมีประสิทธิภาพเมื่อคุณต้องการเปิดใช้งานการยกเว้นซึ่งกันและกันสำหรับคำสั่งเดียวที่คล้ายกันนั้นไม่เป็นความจริงเกี่ยวกับ omp Critical


13
นี่ไม่ใช่อะไรมากไปกว่าการเรียบเรียงคำตอบที่ไม่ดีโดยไม่มีคำอธิบาย
High Performance Mark

-5

atomic เป็นคำสั่งเดียวที่สำคัญคือคุณล็อคสำหรับการดำเนินการคำสั่งเดียว

ส่วนที่สำคัญคือการล็อคบล็อกของรหัส

คอมไพเลอร์ที่ดีจะแปลรหัสที่สองของคุณในลักษณะเดียวกับที่ทำในครั้งแรก


นั่นเป็นสิ่งที่ผิด โปรดอย่าพูดถึงสิ่งที่คุณไม่เข้าใจ
jcsahnwaldt Reinstate Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.