จะเกิดอะไรขึ้นเมื่อฉันปิด () file descriptor?


16

ฉันพยายามดึงภาพทั้งหมดด้วยตัวอธิบายไฟล์ ว่าฉันมี process1 ซึ่งเริ่มมีไฟล์อธิบายเหล่านี้:

 _process1_
|          |
| 0 stdin  |
| 1 stdout |
| 2 stderr |
|__________|

จากนั้นฉันปิดไฟล์ descriptor 1:

close(1);

แฟ้มบ่ง 1 แปล (คะแนน) ที่ stdout โครงสร้างไฟล์ในเคอร์เนลที่เปิดไฟล์ตาราง

ด้วยรหัสด้านบนตัวอธิบายไฟล์ 1 จะถูกลบออกจากตารางกระบวนการซึ่งกลายเป็น:

 _process1_
|          |
| 0 stdin  |
| 2 stderr |
|__________|

แต่จะเกิดอะไรขึ้นในเคอร์เนล? ที่ไม่stdoutโครงสร้างแฟ้มได้รับ deallocated? เป็นไปได้อย่างไรถ้า stdout เป็นไฟล์พิเศษ (มอนิเตอร์) และอาจถูกใช้โดยกระบวนการอื่น ๆ ? สิ่งที่เกี่ยวกับโครงสร้างไฟล์ที่เป็นเพียงไฟล์ปกติ (เช่น. txt) จะเกิดอะไรขึ้นถ้ากระบวนการอื่นกำลังใช้ไฟล์ดังกล่าวอยู่

คำตอบ:


13

file descriptor 1 แปลโครงสร้าง stdout FILE ในตาราง Open Files ของเคอร์เนล

นี่คือความเข้าใจผิด ตารางไฟล์ของเคอร์เนลไม่มีส่วนเกี่ยวข้องกับโครงสร้างไฟล์พื้นที่ผู้ใช้

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

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

ไม่มีโอกาสที่กระบวนการหนึ่งจะปล่อยทรัพยากรที่กระบวนการอื่นกำลังใช้อยู่เนื่องจากทรัพยากรที่ใช้ร่วมกันถูกนับการอ้างอิง


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

ถูกต้องด้วย "อ็อฟเซ็ตไฟล์" ฉันหมายถึงออฟเซ็ตที่การอ่านหรือเขียนครั้งต่อไปจะเกิดขึ้น "ตัวจัดการไฟล์" คือลิงก์ระหว่างกระบวนการและคำอธิบายไฟล์แบบเปิด - เป็นสิ่งที่คุณจะได้รับเมื่อopenประสบความสำเร็จ
David Schwartz

6

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

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

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


1
สองคำถาม: (1) ตัวอธิบายไฟล์อ้างอิงจริงหรือไม่ เมื่อคุณควบคุม -d cat > some.file, cat ได้รับ EOF บน stdin แต่เชลล์ไม่ได้ (2) ทำไมต้องอ้างอิงการนับ ทำไมไม่เก็บขยะบางรูปแบบ? GC นั้นดีกว่าในพื้นที่ของผู้ใช้ไหม?
Bruce Ediger

การขยายคำตอบของ BillThor: ในกรณีปกติ stdin, stdout และ stderr เป็นเพียงการเปิดไฟล์ที่จัดการกับอุปกรณ์ TTY ดังนั้นหากคุณปิดตัวจัดการไฟล์อุปกรณ์ TTY นั้นยังคงอยู่ที่นั่นและยังสามารถเปิดอีกครั้งได้ในภายหลัง
แพทริค

1
@BruceEdiger: (1) เมื่อเปลือกวิ่งcat > some.fileสิ่งที่ทำจริงเป็นฟอร์กเปิดขึ้น some.file 'และกำหนดที่จะอธิบายไฟล์ 1 exec("cat")แล้วมันไม่ เมื่อกระบวนการคือ exec () 'd มันจะสืบทอดตัวอธิบายไฟล์ที่เปิดอยู่
แพทริค

@BruceEdiger (2) การนับการอ้างอิงเป็นรูปแบบที่สมบูรณ์แบบของการรวบรวมขยะเมื่อใช้กับโครงสร้างข้อมูลที่ไม่มีพอยน์เตอร์ไปยัง (หรือเชนของพอยน์เตอร์ที่ลงท้ายด้วย) โครงสร้างข้อมูลอื่นที่เป็นประเภทเดียวกัน นอกจากนี้สิ่งนี้เกิดขึ้นในพื้นที่เคอร์เนล (ไม่ใช่ว่ามันมีความสำคัญมาก)
Gilles 'หยุดชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.