คุณช่วยอธิบายได้ไหมว่าเหตุใดเธรดจำนวนมากต้องการล็อคบน CPU แบบคอร์เดียว


18

สมมติว่าเธรดเหล่านี้ทำงานในซีพียูแกนเดียว ในฐานะที่เป็นซีพียูทำงานเพียงคำสั่งเดียวในรอบ แม้จะคิดว่าพวกเขาแบ่งปันทรัพยากรซีพียู แต่คอมพิวเตอร์รับรองว่าครั้งเดียวหนึ่งคำสั่ง ดังนั้นล็อคไม่จำเป็นสำหรับเธรดหลาย ๆ


เนื่องจากหน่วยความจำทรานแซคชันของซอฟต์แวร์ยังไม่เป็นกระแสหลัก
dan_waterworth

@dan_waterworth เนื่องจากหน่วยความจำทรานแซคชันของซอฟต์แวร์ล้มเหลวอย่างมากในระดับความซับซ้อนที่ไม่สำคัญคุณหมายถึงอะไร? ;)
Mason Wheeler

ฉันจะเดิมพัน Rich Hickey ไม่เห็นด้วยกับสิ่งนั้น
Robert Harvey

@MasonWheeler ในขณะที่การล็อคที่ไม่สำคัญใช้งานได้ดีอย่างน่าอัศจรรย์และไม่เคยเป็นแหล่งที่มาของข้อบกพร่องเล็ก ๆ น้อย ๆ ที่ยากต่อการติดตาม? STM ทำงานได้ดีกับระดับความซับซ้อนที่ไม่ซับซ้อน แต่เป็นปัญหาเมื่อมีการโต้แย้ง ในกรณีเหล่านี้บางสิ่งเช่นนี้ซึ่งเป็นรูปแบบที่เข้มงวดกว่าของ STM นั้นดีกว่า Btw ด้วยการเปลี่ยนชื่อฉันใช้เวลาสักพักแล้วหาสาเหตุว่าทำไมฉันถึงแสดงความคิดเห็นเหมือนฉัน
dan_waterworth

คำตอบ:


32

นี่คือตัวอย่างที่ดีที่สุดด้วยตัวอย่าง

สมมติว่าเรามีงานง่าย ๆ ที่เราต้องการดำเนินการหลาย ๆ ครั้งในแบบคู่ขนานและเราต้องการที่จะติดตามทั่วโลกในจำนวนครั้งที่มีการดำเนินงานเช่นการนับจำนวนการเข้าชมบนหน้าเว็บ

เมื่อแต่ละเธรดมาถึงจุดที่มันเพิ่มจำนวนการประมวลผลจะมีลักษณะดังนี้:

  1. อ่านจำนวนครั้งจากหน่วยความจำในการลงทะเบียนโปรเซสเซอร์
  2. เพิ่มจำนวนนั้น
  3. เขียนตัวเลขนั้นกลับไปที่หน่วยความจำ

โปรดจำไว้ว่าทุกเธรดสามารถระงับได้ทุกเวลาในกระบวนการนี้ ดังนั้นหากเธรด A ดำเนินการตามขั้นตอนที่ 1 และจากนั้นถูกระงับตามด้วยเธรด B ที่ดำเนินการทั้งสามขั้นตอนเมื่อดำเนินการต่อเธรด A การลงทะเบียนจะมีจำนวนครั้งที่ไม่ถูกต้อง: การลงทะเบียนของมันจะถูกคืนค่าอย่างมีความสุข จาก Hit และเก็บหมายเลขที่เพิ่มขึ้นนั้น

นอกจากนี้จำนวนเธรดอื่นใด ๆ ที่สามารถรันได้ในช่วงเวลาที่เธรด A ถูกหยุดชั่วคราวดังนั้นการนับเธรด A ที่เขียนในตอนท้ายอาจต่ำกว่าการนับที่ถูกต้อง

ด้วยเหตุผลดังกล่าวจึงจำเป็นต้องตรวจสอบให้แน่ใจว่าหากเธรดดำเนินการขั้นตอนที่ 1 จะต้องดำเนินการตามขั้นตอนที่ 3 ก่อนที่จะอนุญาตให้เธรดอื่นดำเนินการขั้นตอนที่ 1 ซึ่งสามารถทำได้โดยเธรดทั้งหมดที่รอการล็อกเดี่ยว และการปลดล็อกเฉพาะหลังจากกระบวนการเสร็จสิ้นเพื่อให้โค้ด "ส่วนที่สำคัญ" นี้ไม่สามารถถูกอินเตอร์ลีลอย่างไม่ถูกต้องทำให้เกิดการนับที่ไม่ถูกต้อง

แต่ถ้าปฏิบัติการเป็นอะตอม

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

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

ตั้งแต่แม้ในรหัสแบบมัลติเธรดตัวแปรหลายตัวถูกเก็บไว้ในโลคัลเธรดเดียวโปรแกรมจะมีประสิทธิภาพมากขึ้นหากพวกเขาคิดว่าแต่ละตัวแปรเป็นแบบโลคัลสำหรับเธรดเดี่ยวและให้โปรแกรมเมอร์ดูแลการปกป้องสถานะที่แบ่งใช้ระหว่างเธรด โดยเฉพาะอย่างยิ่งเนื่องจากการปฏิบัติการปรมาณูไม่เพียงพอที่จะแก้ปัญหาการทำเกลียวเช่นที่เราจะเห็นในภายหลัง

ตัวแปรระเหย

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

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

ดังนั้นตัวแปรที่ระบุว่าเป็นสารระเหยจะไม่นำเราไปสู่ดินแดนแห่งการเพิ่มขึ้นของอะตอมเพียง แต่ทำให้เราเข้าใกล้เท่าที่เราคิด

ทำให้อะตอมเพิ่มขึ้น

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

197       /**
198        * Atomically increments by one the current value.
199        *
200        * @return the updated value
201        */
202       public final int incrementAndGet() {
203           for (;;) {
204               int current = get();
205               int next = current + 1;
206               if (compareAndSet(current, next))
207                   return next;
208           }
209       }

วนซ้ำด้านบนทำตามขั้นตอนต่อไปนี้ซ้ำ ๆ จนกระทั่งขั้นตอนที่ 3 สำเร็จ:

  1. อ่านค่าของตัวแปรที่เปลี่ยนแปลงได้โดยตรงจากหน่วยความจำ
  2. เพิ่มมูลค่านั้น
  3. เปลี่ยนค่า (ในหน่วยความจำหลัก) ถ้าหากค่าปัจจุบันในหน่วยความจำหลักนั้นเหมือนกันกับค่าที่เราอ่านในตอนแรกโดยใช้การปฏิบัติการแบบพิเศษของอะตอม

หากขั้นตอนที่ 3 ล้มเหลว (เนื่องจากค่าถูกเปลี่ยนโดยเธรดอื่นหลังจากขั้นตอนที่ 1) มันจะอ่านตัวแปรอีกครั้งโดยตรงจากหน่วยความจำหลักและลองอีกครั้ง

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

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

ดังนั้นเมื่อจำเป็นต้องล็อคอย่างเคร่งครัด?

หากคุณต้องการแก้ไขตัวแปรมากกว่าหนึ่งตัวในการทำงานแบบปรมาณูการล็อกจะจำเป็นคุณจะไม่พบคำสั่งตัวประมวลผลพิเศษสำหรับสิ่งนั้น

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

ลองพิจารณาตัวอย่างที่แต่ละเธรดเพิ่ม 2 เข้ากับตัวแปร X ก่อนแล้วจึงคูณ X ด้วยสอง

ถ้า X เป็นหนึ่งในตอนแรกและมีสองเธรดที่ทำงานอยู่เราคาดว่าผลลัพธ์จะเป็น (((1 + 2) * 2) + 2) * 2 = 16

อย่างไรก็ตามถ้าเธรดสอดแทรกเราสามารถทำได้แม้จะมีการดำเนินการทั้งหมดเป็นอะตอม แต่ก็มีการเพิ่มทั้งคู่เกิดขึ้นก่อนและการคูณจะเกิดขึ้นตามมาทำให้เกิด (1 + 2 + 2) * 2 * 2 = 20

สิ่งนี้เกิดขึ้นเนื่องจากการคูณและการเพิ่มไม่ใช่การดำเนินการสลับ

ดังนั้นการดำเนินการของตัวเองที่เป็นปรมาณูไม่เพียงพอเราต้องทำให้การรวมกันของการดำเนินงานปรมาณู

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

มีการแลกเปลี่ยนหลายอย่างที่เกี่ยวข้อง: เมื่อการคำนวณนานขึ้นมีแนวโน้มมากขึ้นที่เธรดที่กำลังรันจะถูกระงับและค่าจะถูกแก้ไขโดยเธรดอื่นก่อนที่เราจะดำเนินการต่อความหมายของความล้มเหลวมีแนวโน้มมากขึ้น เวลาประมวลผล ในกรณีที่รุนแรงของเธรดจำนวนมากที่มีการคำนวณที่ใช้เวลานานมากเราอาจมี 100 เธรดอ่านตัวแปรและมีส่วนร่วมในการคำนวณในกรณีนี้เฉพาะการจบครั้งแรกเท่านั้นที่จะประสบความสำเร็จในการเขียนค่าใหม่ ทำการคำนวณให้เสร็จ แต่พบว่าพวกเขาไม่สามารถอัปเดตค่า ... ณ จุดที่พวกเขาแต่ละคนจะอ่านค่าและเริ่มการคำนวณ เราน่าจะมี 99 กระทู้ที่เหลือทำซ้ำปัญหาเดียวกันทำให้เสียเวลาในการประมวลผลจำนวนมหาศาล

การทำให้เป็นอนุกรมอย่างสมบูรณ์ของส่วนที่สำคัญผ่านการล็อคจะดีกว่ามากในสถานการณ์นั้น: 99 เธรดจะระงับเมื่อพวกเขาไม่ได้รับการล็อคและเราจะเรียกใช้แต่ละเธรดเพื่อให้มาถึงที่จุดล็อค

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


แต่จะเกิดอะไรขึ้นถ้าตัวนับที่เพิ่มขึ้นคืออะตอมจำเป็นต้องล็อคหรือไม่
pythonee

@pythonee: หากการเพิ่มขึ้นของตัวนับเป็นอะตอมก็อาจจะไม่ได้ แต่ในโปรแกรมแบบมัลติเธรดที่มีขนาดที่เหมาะสมคุณจะมีงานที่ไม่ใช่อะตอมที่ต้องทำบนทรัพยากรที่ใช้ร่วมกัน
Doc Brown

1
หากคุณไม่ได้ใช้คอมไพเลอร์ภายในเพื่อเพิ่มอะตอมมิกมันอาจไม่ใช่
Mike Larsen

ใช่ถ้าการอ่าน / แก้ไข (เพิ่มขึ้น) / การเขียนเป็นอะตอมการล็อคไม่จำเป็นสำหรับการดำเนินการนั้น DEC-10 AOSE (เพิ่มและข้ามถ้าคำสั่ง result == 0) ถูกสร้างขึ้นเป็นพิเศษโดยอะตอมดังนั้นมันจึงสามารถใช้เป็นเซมาฟอร์ทดสอบและเซ็ตได้ คู่มือกล่าวว่ามันดีพอเพราะจะต้องใช้เวลาหลายวันในการนับเครื่องอย่างต่อเนื่องเพื่อม้วนตัวลงทะเบียนแบบ 36 บิตไปจนหมด อย่างไรก็ตามในตอนนี้ไม่ใช่ทุกสิ่งที่คุณทำจะเป็น "เพิ่มหนึ่งหน่วยความจำ"
John R. Strohm

ฉันได้อัปเดตคำตอบของฉันเพื่อแก้ไขข้อกังวลเหล่านี้: ใช่คุณสามารถทำให้การดำเนินการของอะตอมได้ แต่ไม่ใช่แม้แต่กับสถาปัตยกรรมที่รองรับมันจะไม่เป็นอะตอมโดยค่าเริ่มต้นและมีสถานการณ์ที่อะตอมไม่ได้ เพียงพอและต่อเนื่องเป็นสิ่งจำเป็น การล็อคเป็นกลไกเดียวที่ฉันรับรู้เพื่อให้ได้การทำให้เป็นอนุกรมทั้งหมด
Theodore Murdock

4

พิจารณาคำพูดนี้:

บางคนเมื่อต้องเผชิญกับปัญหาคิดว่า "ฉันรู้ว่าฉันจะใช้หัวข้อ" แล้วพวกเขาทั้งสองมี poblesms haver

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


ฉันคิดว่าการเสนอราคาเป็นนิพจน์ทั่วไปไม่ใช่เธรด
user16764

3
เครื่องหมายคำพูดมีผลบังคับใช้กับเธรดสำหรับฉันมากขึ้น (ด้วยคำ / ตัวอักษรที่ถูกพิมพ์ออกมาเนื่องจากปัญหาเธรด) แต่ในปัจจุบันมี "s" พิเศษในผลลัพธ์ซึ่งแสดงว่ารหัสมีปัญหาสามประการ
Theodore Murdock

1
มันเป็นผลข้างเคียง บางครั้งคุณสามารถเพิ่ม 1 บวก 1 และรับ 4294967295 :)
gbjbaanb

3

ดูเหมือนว่ามีคำตอบมากมายที่พยายามอธิบายการล็อก แต่ฉันคิดว่าสิ่งที่ OP ต้องการคือคำอธิบายว่ามัลติทาสกิ้งคืออะไร

เมื่อคุณมีมากกว่าหนึ่งเธรดที่ทำงานบนระบบแม้จะมีหนึ่ง CPU มีวิธีการหลักสองวิธีที่กำหนดว่าเธรดเหล่านี้จะถูกกำหนดเวลาไว้อย่างไร (เช่นถูกวางให้ทำงานในซีพียูแบบแกนเดี่ยว):

  • Cooperative Multitasking - ใช้ใน Win9x ซึ่งต้องใช้แต่ละแอปพลิเคชันเพื่อยกเลิกการควบคุมอย่างชัดเจน ในกรณีนี้คุณไม่จำเป็นต้องกังวลเกี่ยวกับการล็อคเนื่องจากตราบใดที่เธรด A กำลังดำเนินการอัลกอริทึมคุณจะรับประกันได้ว่ามันจะไม่ถูกขัดจังหวะ
  • Preemptive Multitasking - ใช้ในระบบปฏิบัติการที่ทันสมัยที่สุด (Win2k และใหม่กว่า) สิ่งนี้ใช้ timeslices และจะขัดจังหวะเธรดแม้ว่าพวกเขาจะยังคงทำงานอยู่ สิ่งนี้มีความแข็งแกร่งมากขึ้นเนื่องจากเธรดเดียวไม่สามารถแขวนเครื่องทั้งหมดของคุณได้ซึ่งเป็นไปได้อย่างแท้จริงกับการทำงานมัลติทาสก์แบบร่วมมือกัน ในทางตรงกันข้ามตอนนี้คุณต้องกังวลเกี่ยวกับการล็อคเพราะในเวลาใดก็ตามหนึ่งในกระทู้ของคุณอาจถูกขัดจังหวะ (เช่นจองไว้ล่วงหน้า) และระบบปฏิบัติการอาจกำหนดเวลาเธรดที่แตกต่างกันในการทำงาน เมื่อโค้ดแอปพลิเคชันแบบมัลติเธรดที่มีลักษณะการทำงานนี้คุณต้องพิจารณาว่าระหว่างโค้ดทุกบรรทัด (หรือแม้แต่คำสั่งทุกคำสั่ง) เธรดอื่นอาจทำงานได้ ในขณะนี้แม้จะมีแกนเดียวการล็อคก็มีความสำคัญมากเพื่อให้แน่ใจว่าสถานะของข้อมูลของคุณสอดคล้องกัน

0

ปัญหาไม่ได้อยู่ที่การปฏิบัติงานของแต่ละบุคคล

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

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

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

อีกสิ่งหนึ่งที่การซิงโครไนซ์แบบดั้งเดิมมีแนวโน้มที่จะส่งผลให้ในบางแพลตฟอร์มคือพวกมันปล่อยสิ่งกีดขวางหน่วยความจำซึ่งทำให้มั่นใจได้ถึงความสอดคล้องของหน่วยความจำระหว่างซีพียู


0

ยกเว้นการตั้งค่า 'บูล' ไม่มีการรับประกัน (อย่างน้อยใน c) ว่าการอ่านหรือการเขียนตัวแปรใช้คำสั่งเดียวเท่านั้น - หรือไม่สามารถถูกขัดจังหวะในระหว่างการอ่าน / เขียน


มีคำแนะนำกี่วิธีในการตั้งค่าจำนวนเต็ม 32 บิต
DXM

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

1
แนวคิดของการเรียนการสอนเดี่ยวในซีพียูที่มีการขยายตัวสูง / มัลติคอร์ / สาขาที่คาดการณ์ / มัลติแคชนั้นค่อนข้างยุ่งยาก แต่มาตรฐานบอกว่าเพียง 'บูล' เท่านั้นที่จะต้องปลอดภัยต่อบริบทของสวิทช์กลางอ่าน / เขียน ของตัวแปรเดียว มีการเพิ่ม :: Atomic ซึ่งล้อม mutex รอบประเภทอื่น ๆ และฉันคิดว่า c ++ 11 เพิ่ม guarrantees เธรดเพิ่มเติม
Martin Beckett

the standard says that only 'bool' needs to be safe against a context switch in the middle of a read/write of a single variableควรเพิ่มคำอธิบายลงในคำตอบจริงๆ
Wolf

0

แชร์หน่วยความจำ

มันเป็นคำจำกัดความของ ... กระทู้ : พวงของกระบวนการที่เกิดขึ้นพร้อมกันกับหน่วยความจำที่ใช้ร่วมกัน

หากไม่มีการใช้ร่วมกันหน่วยความจำที่พวกเขามักจะเรียกว่าเป็นโรงเรียนเก่า-UNIXกระบวนการ
พวกเขาอาจต้องล็อคตอนนี้และเมื่อเข้าถึงไฟล์ที่ใช้ร่วมกัน

(หน่วยความจำที่ใช้ร่วมกันในเคอร์เนลที่คล้าย UNIX โดยปกติแล้วจะใช้งานโดยใช้ file descriptor ปลอมแทนที่อยู่หน่วยความจำที่ใช้ร่วมกัน)


0

CPU รันหนึ่งคำสั่งพร้อมกัน แต่จะเกิดอะไรขึ้นถ้าคุณมี CPU สองตัวขึ้นไป

คุณมีสิทธิ์ในการล็อคที่ไม่จำเป็นถ้าคุณสามารถเขียนโปรแกรมเพื่อใช้ประโยชน์จากคำสั่งอะตอม: คำแนะนำที่การดำเนินการไม่ถูกขัดจังหวะในโปรเซสเซอร์ที่กำหนดและปราศจากการแทรกแซงจากโปรเซสเซอร์อื่น ๆ

ต้องมีการล็อคเมื่อจำเป็นต้องป้องกันหลายคำแนะนำจากสัญญาณรบกวนและไม่มีคำสั่งอะตอมมิกเทียบเท่า

ตัวอย่างเช่นการแทรกโหนดในรายการที่ลิงก์เป็นสองเท่าต้องมีการอัพเดตตำแหน่งหน่วยความจำหลายแห่ง ก่อนการแทรกและหลังการแทรกค่าคงที่บางค่าคงที่เกี่ยวกับโครงสร้างของรายการ อย่างไรก็ตามในระหว่างการแทรกค่าคงที่เหล่านั้นจะถูกทำลายชั่วคราว: รายการอยู่ในสถานะ "ภายใต้การก่อสร้าง"

หากเธรดอื่นเดินผ่านรายการในขณะที่ค่าคงที่หรือพยายามแก้ไขเมื่อสถานะเป็นเช่นนั้นโครงสร้างข้อมูลอาจเสียหายและพฤติกรรมไม่สามารถคาดเดาได้: ซอฟต์แวร์อาจทำงานผิดพลาดหรืออาจดำเนินการต่อด้วยผลลัพธ์ที่ไม่ถูกต้อง ดังนั้นจึงเป็นเรื่องจำเป็นสำหรับเธรดที่ตกลงกันว่าจะหลีกทางให้กันเมื่อรายการถูกอัพเดต

รายการที่ได้รับการออกแบบอย่างเหมาะสมสามารถจัดการได้ด้วยคำแนะนำอะตอมมิกดังนั้นจึงไม่จำเป็นต้องล็อค อัลกอริทึมสำหรับสิ่งนี้เรียกว่า "ล็อคฟรี" อย่างไรก็ตามโปรดทราบว่าคำแนะนำอะตอมเป็นรูปแบบของการล็อคจริง มีการใช้งานเป็นพิเศษในฮาร์ดแวร์และทำงานผ่านการสื่อสารระหว่างโปรเซสเซอร์ พวกเขามีราคาแพงกว่าคำแนะนำที่คล้ายกันซึ่งไม่ใช่อะตอม

บนมัลติโปรเซสเซอร์ที่ไม่มีคำสั่งปรมาณูขั้นพื้นฐานสำหรับการยกเว้นซึ่งกันและกันจะต้องสร้างการเข้าถึงหน่วยความจำอย่างง่ายและการวนซ้ำแบบสำรวจ ปัญหาดังกล่าวเกิดขึ้นโดย Edsger Dijkstra และ Leslie Lamport


FYI ฉันได้อ่านอัลกอริธึมที่ไม่ล็อคเพื่อดำเนินการอัปเดตรายการที่ลิงก์สองเท่าโดยใช้การเปรียบเทียบและการสลับเพียงครั้งเดียว นอกจากนี้ฉันอ่านกระดาษสีขาวเกี่ยวกับสิ่งอำนวยความสะดวกซึ่งดูเหมือนว่าจะมีราคาถูกกว่าในฮาร์ดแวร์มากกว่า double-compar-and-swap (ซึ่งถูกนำมาใช้ใน 68040 แต่ไม่ได้ดำเนินการผ่านโปรเซสเซอร์ 68xxx อื่น ๆ ): ขยายโหลด -linked / store-conditional เพื่อให้โหลดสองลิงค์และร้านค้าแบบมีเงื่อนไข แต่ด้วยเงื่อนไขที่ว่าการเข้าถึงที่เกิดขึ้นระหว่างสองร้านจะไม่ย้อนกลับไปก่อน นั่นเป็นเรื่องง่ายกว่าที่จะนำไปใช้มากกว่าการเปรียบเทียบกับร้านค้าสองเท่า ...
supercat

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