เธรดมีฮีปที่แตกต่างกันหรือไม่?


114

เท่าที่ฉันรู้ว่าแต่ละเธรดได้รับสแต็กที่แตกต่างกันเมื่อเธรดถูกสร้างขึ้นโดยระบบปฏิบัติการ ฉันสงสัยว่าแต่ละเธรดมีฮีปที่แตกต่างกันหรือไม่?


ใช่ windows และ linux ไลบรารี c

3
ดี +1 ให้คำถามพื้นฐานเหล่านั้นตามมา

คำตอบ:


128

ไม่เธรดทั้งหมดใช้ฮีปร่วมกัน

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

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

บางภาษาอนุญาตให้คุณสร้างพูลหน่วยความจำส่วนตัวหรือแต่ละฮีปซึ่งคุณสามารถกำหนดให้กับเธรดเดียวได้


5
โดยทั่วไปเธรดจะใช้ทรัพยากรร่วมกันเช่นหน่วยความจำดังนั้นการใช้เธรดที่ไม่ได้ใช้งานร่วมกันจะแชร์ฮีป
R.Martinho Fernandes

10
หลักเหตุผลแต่ละหัวข้อมีสแต็คของตัวเองเพื่อให้ด้ายจริงสามารถทำบางสิ่งบางอย่าง (เช่นโทรฟังก์ชั่น) ...
เอ๊ดมันด์

3
ทุกเธรดมีสแต็กแยกกัน แต่ไม่จำเป็นต้องเป็น "ส่วนตัว" โดยปกติเธรดอื่น ๆ จะได้รับอนุญาตให้เข้าถึงได้
zch

you will get a stack overflow.กองซ้อนบน Stack Overflow!
John Strood

2
@crisron เป็นไปได้ที่จะตั้งค่าฮีปแยกต่างหากสำหรับแต่ละเธรด แต่ถ้าคุณทำเช่นนั้นแทนที่จะใช้ฮีปที่แบ่งใช้เริ่มต้นก็จะยากเช่นเธรด A ในการจัดสรรบัฟเฟอร์เติมข้อมูลส่งต่อไปยังเธรด B และให้เธรด B ใช้ข้อมูลจากนั้นจึงเพิ่มบัฟเฟอร์ (เนื่องจากเธรด B ไม่สามารถเข้าถึงฮีปของเธรด A เธรด B จึงไม่สามารถเพิ่มบัฟเฟอร์ได้เธรดที่ดีที่สุด B สามารถทำได้คือส่งบัฟเฟอร์กลับไปที่เธรด A อีกครั้งและมีเธรด A ฟรี)
Jeremy Friesner

9

โดยค่าเริ่มต้น C จะมีฮีปเดียวเท่านั้น

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

ตัวอย่างหนึ่งของกองดังกล่าวเป็นของสะสม


โดยค่าเริ่มต้น C และ C ++ ไม่มีหลายเธรด อย่างน้อยข้อกำหนด 2003 c ++ ไม่ได้ให้ค่าเผื่อสำหรับเธรดในการออกแบบเครื่องเสมือนดังนั้นเธรดใน c ++ จึงถูกกำหนดการใช้งาน
Chris Becke

แม้ว่าเธรดที่แตกต่างกันจะมีพื้นที่ที่แตกต่างกันในการจัดสรรจากฮีป แต่ก็ยังสามารถเห็นข้อมูลที่จัดสรรโดยเธรดอื่นดังนั้นเธรดจึงยังคงแชร์ฮีปเดียวกัน
Ken Bloom

1
อัปเดต: เนื่องจาก C ++ 11 เธรดไม่ได้กำหนดการใช้งานอีกต่อไป
Michael Dorst

5

ขึ้นอยู่กับระบบปฏิบัติการ รันไทม์ c มาตรฐานบน windows และ unices ใช้ฮีปที่แบ่งใช้ข้ามเธรด ซึ่งหมายถึงการล็อคทุก malloc / ฟรี

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

Erlang ยังทำตามการออกแบบที่คล้ายกันโดยที่ "กระบวนการ" ทำหน้าที่เป็นหน่วยเก็บขยะ ข้อมูลทั้งหมดได้รับการสื่อสารระหว่างกระบวนการโดยการคัดลอกยกเว้น binary blobs ที่นับการอ้างอิง (ฉันคิดว่า)


3

แต่ละเธรดมีสแต็กและโทรสแต็กของตัวเอง

แต่ละเธรดแชร์ฮีปเดียวกัน


3

ขึ้นอยู่กับว่าคุณหมายถึงอะไรเมื่อพูดว่า "heap"

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

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


1

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


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

2
fork () สามารถใช้งานได้หลายกรณีซึ่งอาจใช้เธรดได้ด้วย เนื่องจากการคัดลอกเมื่อเขียนจึงไม่มีความแตกต่างด้านต้นทุนอย่างมีนัยสำคัญในระบบ Unix กรณีการใช้งานทั่วไปคือการที่ผู้ปฏิบัติงานเป็นอิสระ (เช่นเว็บเซิร์ฟเวอร์) จากส่วนที่เหลือของบริการ ความเป็นไปได้อีกประการหนึ่งคือการสื่อสารผ่าน stdin / out กับเธรดหลัก / โปรแกรม fork () แข็งแกร่งใน Unix ในขณะที่แพลตฟอร์มอื่น ๆ เช่น Windows ชอบเธรด เหตุผลหลักอาจเป็นเพราะการใช้ fork () นั้นง่ายและปลอดภัยกว่ามากและ Unix มีปรัชญาความเรียบง่ายนี้ ดูตัวอย่างเว็บเซิร์ฟเวอร์ apache ที่มีการเปลี่ยนไปใช้เธรดช้า
ypnos

1

โดยทั่วไปแล้วเธรดทั้งหมดจะใช้พื้นที่แอดเดรสเดียวกันดังนั้นจึงมักจะมีฮีปเดียว

อย่างไรก็ตามอาจซับซ้อนกว่าเล็กน้อย คุณอาจกำลังมองหาThread Local Storage (TLS) แต่จะเก็บค่าเดียวเท่านั้น

เฉพาะ Windows: สามารถจัดสรรพื้นที่ TLS โดยใช้TlsAllocและปล่อยให้เป็นอิสระโดยใช้TlsFree (ภาพรวมที่นี่ ) อีกครั้งมันไม่ใช่กองเป็นเพียง DWORD

น่าแปลกที่ Windows รองรับหลายHeapsต่อกระบวนการ หนึ่งสามารถจัดเก็บที่จับของ Heap ใน TLS จากนั้นคุณจะมีบางอย่างเช่น "Thread-Local Heap" อย่างไรก็ตามเธรดอื่น ๆ ไม่รู้จักแค่ที่จับ แต่ยังสามารถเข้าถึงหน่วยความจำได้โดยใช้พอยน์เตอร์เนื่องจากยังคงเป็นพื้นที่แอดเดรสเดียวกัน

แก้ไข : ตัวจัดสรรหน่วยความจำบางตัว (โดยเฉพาะjemallocบน FreeBSD) ใช้ TLS เพื่อกำหนด "arenas" ให้กับเธรด สิ่งนี้ทำเพื่อเพิ่มประสิทธิภาพการจัดสรรสำหรับหลายคอร์โดยลดค่าใช้จ่ายในการซิงโครไนซ์


> "น่าแปลกที่ Windows รองรับ Heaps หลายรายการต่อกระบวนการ" ไม่แปลกเลยเราสามารถใช้ฮีปที่แตกต่างกันสำหรับการจัดสรรประเภทต่างๆเพียงแค่เพิ่มความยืดหยุ่นมากขึ้น แน่นอนว่าคุณสามารถลง VirtualAlloc ได้ตลอดเวลาและสร้างฮีปของคุณเองตามที่คุณต้องการ

1

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

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