- NT มักถูกประเมินว่าเป็นระบบปฏิบัติการที่ "ก้าวหน้ามาก" แต่ผู้เขียนก็ไม่ค่อยรู้เหตุผลนัก
- ปลายปี 2023 ผู้เขียนได้อ่าน Inside Windows NT ฉบับพิมพ์ครั้งที่ 1 แล้วจึงตัดสินใจเปรียบเทียบ NT กับ Unix
- นี่คือการเปรียบเทียบการออกแบบของ NT (กรกฎาคม 1993) กับระบบ Unix ในยุคนั้น (4.4BSD, Linux 1.0)
- ในฐานะผู้เชี่ยวชาญ Unix ผู้เขียนไม่ค่อยรู้จัก NT มากนัก จึงจะอธิบายโดยเน้นที่ความแตกต่างของ NT เป็นหลัก
- เนื้อหานี้ตั้งคำถามว่า NT ดีกว่า Unix ในจุดใด และปัจจุบันยังเป็นเช่นนั้นอยู่หรือไม่
ภารกิจ
- ประวัติของ Unix ยาวนานกว่า NT มาก
- การพัฒนา Unix เริ่มขึ้นในปี 1969 และเป้าหมายหลักคือการเป็นแพลตฟอร์มที่สะดวกสำหรับโปรแกรมเมอร์
- Unix ได้แรงบันดาลใจจาก Multics แต่เหนือกว่า Multics ด้วยการมุ่งเน้นความเรียบง่าย
- ความสามารถในการพกพาข้ามระบบและมัลติทาสกิงไม่ใช่เป้าหมายดั้งเดิมของการออกแบบ Unix: ฟีเจอร์เหล่านี้ถูกเพิ่มเข้ามาในภายหลังจาก "fork" และการคิดค้น Unix ใหม่จำนวนมากในอีกหลายปีต่อมา
- ประวัติของ Microsoft
- MS-DOS รุ่นแรกออกในเดือนสิงหาคม 1981 และ "Windows แบบเดิม" (เวอร์ชันที่ทำงานบน DOS) รุ่นแรกออกในเดือนพฤศจิกายน 1985
- แม้ MS-DOS จะประสบความสำเร็จอย่างกว้างขวาง แต่ Windows เริ่มมีความสำคัญอย่างแท้จริงตั้งแต่ Windows 3.0 ในเดือนพฤษภาคม 1990
- Windows NT ถูกวางแนวคิดขึ้นในปี 1989 และปรากฏสู่โลกด้วยการออก NT 3.1 ในเดือนกรกฎาคม 1993
- ข้อได้เปรียบของ Microsoft
- การออกแบบ NT เริ่มต้นช้ากว่า Unix 20 ปี ซึ่งเป็นข้อได้เปรียบสำหรับ Microsoft
- Microsoft มีฐานผู้ใช้ขนาดใหญ่จาก MS-DOS และ Windows แบบเดิมอยู่แล้ว
- ทีม Microsoft ที่ออกแบบ NT มีทั้งข้อมูลเชิงลึกจากการพัฒนาเหล่านี้ ประสบการณ์จากการพัฒนาระบบปฏิบัติการอื่น ๆ และการเข้าถึงเทคโนโลยีสมัยใหม่ ทำให้สามารถ "เล็งไปให้สุด" ในการสร้าง NT ได้
เคอร์เนล
- Unix ถูกนำไปใช้งานเป็นโมโนลิธิกเคอร์เนลเกือบทั้งหมด ยกเว้นบางกรณีอย่าง Minix หรือ GNU Hurd และเปิดเผยชุด system call สำหรับโต้ตอบกับฟังก์ชันที่ระบบปฏิบัติการมีให้
- ในทางกลับกัน NT อยู่กึ่งกลางระหว่างโมโนลิธิกเคอร์เนลกับไมโครเคอร์เนล: คอมโพเนนต์สิทธิพิเศษอย่าง executive แสดงตัวเองต่อ subsystems ใน user space ในรูปของชุดคอมโพเนนต์แบบโมดูลาร์
- subsystems ใน user space คือโปรเซสพิเศษที่ทำหน้าที่ "แปลง" API ที่แอปพลิเคชันใช้ (POSIX, OS/2 ฯลฯ) ให้เป็น executive system call
- หนึ่งในส่วนสำคัญของ NT executive คือ HAL ซึ่งให้ primitive abstraction สำหรับเข้าถึงฮาร์ดแวร์ของเครื่อง และทำหน้าที่เป็นรากฐานให้กับส่วนที่เหลือของเคอร์เนล
- เลเยอร์นี้คือหัวใจสำคัญที่ทำให้ NT สามารถทำงานได้บนสถาปัตยกรรมหลากหลาย รวมถึง i386, Alpha และ PowerPC
- Unix ในเวลานั้นยังผูกติดกับสถาปัตยกรรมเฉพาะ: แนวคิดของ Unix ย้ายข้ามระบบได้ แต่ตัว implementation ยังไม่ใช่
- เดิม SunOS รองรับเฉพาะ Motorola 68000, 386BSD เป็นการพอร์ต BSD มายังสถาปัตยกรรม Intel ครั้งแรก และ IRIX ก็เป็น Unix สายพันธุ์หนึ่งสำหรับเวิร์กสเตชัน MIPS ของ Silicon Graphics
- อีกส่วนสำคัญของ NT executive คือการรองรับระบบมัลติโปรเซสซิงและเคอร์เนลแบบ preemptive
- ในเคอร์เนลมีระดับ interrupt หลายระดับ (ในศัพท์ของ BSD เรียกว่า SPL) เพื่อกำหนดว่าอะไรสามารถขัดจังหวะอะไรได้ แต่สิ่งที่สำคัญกว่าคือเคอร์เนลเธรดสามารถถูก preempt โดยเคอร์เนลเธรดอื่นได้
- ปัจจุบันระบบ Unix สมรรถนะสูงทั้งหมดทำแบบนี้ แต่ Unix จำนวนมากไม่ได้เริ่มต้นมาเช่นนั้น
- ระบบเหล่านี้เริ่มจากเคอร์เนลที่ไม่รองรับทั้ง preemption และมัลติโปรเซสซิง จากนั้นจึงเพิ่มการรองรับมัลติโปรเซสซิงใน user space แล้วค่อยเพิ่ม kernel preemption
- ขั้นตอนสุดท้ายเป็นขั้นตอนที่ยากที่สุด และมหากาพย์ FreeBSD 5.0 ก็แสดงให้เห็นถึงความท้าทายนั้น
- ดังนั้นจึงน่าสนใจที่ NT เริ่มต้นมาด้วยรากฐานที่ถูกต้องตั้งแต่แรก
อ็อบเจ็กต์
- NT เป็นเคอร์เนลเชิงวัตถุ
- คุณอาจคิดว่า Unix ก็เป็นเช่นนั้น: โปรเซสถูกนิยามด้วย struct และ implementation ของไฟล์ซิสเต็มก็จัดการกับ vnode ("virtual node" อย่าสับสนกับ inode)
- แต่สิ่งนี้ไม่เหมือนกับที่ NT ทำเสียทีเดียว: NT บังคับให้อ็อบเจ็กต์ทุกชนิดเหล่านี้มีตัวแทนแบบร่วมกันภายในระบบ
- อาจสงสัยว่าจะสร้าง abstraction ที่มีความหมายให้กับสิ่งที่ต่างกันมากอย่างโปรเซสกับ file handle ได้อย่างไร
- ในทางปฏิบัติทำไม่ได้ทั้งหมด แต่ NT บังคับให้สิ่งเหล่านี้ทั้งหมดสืบทอดจากชนิดอ็อบเจ็กต์ร่วมกัน และน่าแปลกที่มันให้คุณสมบัติที่ดีบางอย่าง
- การควบคุมการเข้าถึงแบบรวมศูนย์
- อ็อบเจ็กต์ถูกสร้างได้โดย object manager เท่านั้น จึงมีจุดเดียวของโค้ดสำหรับบังคับใช้นโยบาย
- ความหมายอย่างการตรวจสอบสิทธิ์สามารถถูกกำหนดไว้เพียงจุดเดียวและบังคับใช้อย่างสม่ำเสมอทั่วทั้งระบบ ซึ่งทรงพลังมาก
- NetBSD ก็สรุปว่าแนวคิดนี้ดีเช่นกัน แต่ต้องรอถึงปี 2001 จึงได้เฟรมเวิร์ก Kernel Authorization (kauth)
- ID ร่วมกัน
- อ็อบเจ็กต์มี ID และทั้งหมดถูกแสดงอยู่ในต้นไม้เดียว
- นี่หมายความว่ามี namespace ที่เป็นเอกลักษณ์สำหรับอ็อบเจ็กต์ทุกชนิด ไม่ว่าจะเป็นโปรเซส file handle หรือ pipe
- อ็อบเจ็กต์ในต้นไม้สามารถระบุที่อยู่ได้ด้วยชื่อ (path) และส่วนต่าง ๆ ของต้นไม้อาจเป็นของ subsystem ที่ต่างกัน
- ตัวอย่างเช่น ส่วนหนึ่งของต้นไม้อาจแทนไฟล์ซิสเต็มที่ถูก mount อยู่ ดังนั้นเมื่อไล่ไปถึงโหนดรากของ subtree นั้นแล้ว ไฟล์ซิสเต็มก็จะเป็นผู้ resolve ส่วนที่เหลือของ path
- สิ่งนี้คล้ายกับเลเยอร์ VFS ของระบบ Unix แต่ VFS จัดการเฉพาะไฟล์ซิสเต็ม ขณะที่ object tree ครอบคลุม อ็อบเจ็กต์ในเคอร์เนลทุกชนิด
- Unix พยายามยัดอ็อบเจ็กต์ที่ไม่ใช่ไฟล์ลงในไฟล์ซิสเต็มผ่าน
/proc/, /sys/ เป็นต้น แต่เมื่อเทียบกับสิ่งที่ NT มีให้แล้ว มันให้ความรู้สึกเหมือนเป็นการแก้ทีหลัง
- การจัดการอีเวนต์แบบบูรณาการ
- อ็อบเจ็กต์ทุกชนิดมีสถานะ signaled แต่ความหมายของมันแตกต่างกันไปตามชนิดของอ็อบเจ็กต์
- ตัวอย่างเช่น อ็อบเจ็กต์โปรเซสจะเปลี่ยนเป็นสถานะ signaled เมื่อโปรเซสสิ้นสุดลง และอ็อบเจ็กต์ file handle จะเปลี่ยนเป็นสถานะ signaled เมื่อคำขอ I/O เสร็จสิ้น
- สิ่งนี้ทำให้การเขียนโค้ดแบบอิงอีเวนต์ (โค้ด async) ใน user space ง่ายมาก เพราะ system call แบบ wait เพียงแบบเดียวก็สามารถรอให้อ็อบเจ็กต์กลุ่มหนึ่งเปลี่ยนสถานะได้
- ในระบบ Unix การรอทั้ง I/O และการจบของโปรเซสพร้อมกันเป็นเรื่องน่าปวดหัว
- อ็อบเจ็กต์เป็นองค์ประกอบเฉพาะของ NT และไม่ได้ทำให้เป็นนามธรรมร่วมได้ดีกับทุก API ที่ NT ต้องการรองรับ
- ตัวอย่างเช่น POSIX subsystem: POSIX ไม่มีแนวคิดเรื่องอ็อบเจ็กต์แบบ NT แต่ NT ก็ต้องให้ความเข้ากันได้บางระดับกับแอปพลิเคชัน POSIX
- ด้วยเหตุนี้ ขณะที่ POSIX subsystem จัดสรรอ็อบเจ็กต์จาก executive มันก็ต้องเก็บบันทึกของตัวเองเพื่อแทนเอนทิตีแบบ POSIX และทำการแปลงเชิงตรรกะระหว่างสองเอนทิตีนี้ทันที
- ในทางกลับกัน Win32 subsystem ส่งมอบอ็อบเจ็กต์ให้ client โดยตรงโดยไม่ต้องมีตัวกลาง
โปรเซส
- โปรเซสเป็นอ็อบเจ็กต์ที่ NT และ Unix มีร่วมกัน แต่ไม่ได้เหมือนกันทั้งหมด
- ใน Unix โปรเซสจะแสดงเป็นต้นไม้ โดยแต่ละโปรเซสมีโปรเซสแม่ และโปรเซสหนึ่ง ๆ สามารถมีโปรเซสลูกได้ตั้งแต่ 0 ตัวขึ้นไป
- แต่ใน NT ไม่มีความสัมพันธ์แบบนั้น: โปรเซสสามารถ "สืบทอด" ทรัพยากรจากตัวสร้างได้ แต่หลังจากถูกสร้างแล้วจะเป็นเอนทิตีอิสระ
- ในช่วงที่ NT ถูกออกแบบ เธรดยังไม่ใช่เรื่องแพร่หลาย:
- Mach เป็นเคอร์เนลลักษณะ Unix ตัวแรกที่รวมเธรดเข้าไว้ในปี 1985
- นั่นหมายความว่า Unix อื่น ๆ ต้องนำแนวคิดนี้มาใช้ภายหลังและดัดแปลงให้เข้ากับการออกแบบเดิม
- Linux เลือกในรีลีส 2.0 เมื่อเดือนมิถุนายน 1996 ที่จะแสดงเธรดเป็นโปรเซสซึ่งแต่ละตัวมี PID ของตัวเอง ส่วน NetBSD ต้องรอจนถึงรีลีส 2.0 ในปี 2004 จึงมีเธรดที่แสดงเป็นเอนทิตีแยกจากโปรเซส
- ต่างจาก Unix, NT เลือกสนับสนุนเธรดมาตั้งแต่แรก เพราะรู้ว่าเธรดเป็นสิ่งจำเป็นสำหรับการประมวลผลสมรรถนะสูงบนเครื่อง SMP
- NT ไม่มี signal ในความหมายแบบ Unix ดั้งเดิม
- แต่มี alerts แทน ซึ่งอาจเป็นได้ทั้งโหมดเคอร์เนลและโหมดผู้ใช้
- การแจ้งเตือนโหมดผู้ใช้ต้องรอเหมือนกับอ็อบเจ็กต์อื่น ๆ และการแจ้งเตือนโหมดเคอร์เนลจะมองไม่เห็นสำหรับโปรเซส
- ระบบย่อย POSIX ใช้การแจ้งเตือนโหมดเคอร์เนลเพื่อจำลอง signal
- signal มักถูกเรียกว่าเป็นตำหนิของ Unix เพราะวิธีที่มันขัดจังหวะการทำงานของโปรเซส: การจัดการ signal ให้ถูกต้องเป็นงานที่ยากมาก ดังนั้นทางเลือกของ NT จึงดูสง่างามกว่า
- พัฒนาการที่น่าสนใจล่าสุดใน NT คือการนำ pico process เข้ามาใช้
- ก่อนเพิ่มความสามารถนี้ โปรเซสของ NT ค่อนข้างหนัก: โปรเซสใหม่จะได้รับชุดไลบรารีรันไทม์ของ NT ที่แมปเข้ามาในแอดเดรสสเปซตั้งแต่เริ่มต้น
- ใน pico process ตัวโปรเซสมีความผูกพันกับสถาปัตยกรรม Windows เพียงเล็กน้อย และถูกใช้ในการทำโปรเซสที่เข้ากันได้กับ Linux ใน WSL 1
- ในบางแง่ pico process ใกล้เคียงกับโปรเซสแบบ Unix มากกว่าโปรเซส Windows พื้นฐาน แต่จากการย้ายไป WSL 2 ทำให้มันไม่ค่อยถูกใช้อีกแล้ว แม้จะมีมาตั้งแต่เดือนสิงหาคม 2016
- แม้จะมีการตำหนิประเด็นความปลอดภัยของ Windows อยู่มาก แต่ NT เริ่มต้นมาพร้อมการออกแบบความปลอดภัยที่ก้าวหน้าสำหรับมาตรฐานอินเทอร์เน็ตยุคแรก ๆ โดยระบบทำงานในลักษณะ capability-based โดยพื้นฐาน
- โปรเซสผู้ใช้ตัวแรกที่เริ่มหลังการล็อกอินจะได้รับ access token จากเคอร์เนล ซึ่งแสดงสิทธิ์ของเซสชันผู้ใช้ และโปรเซสกับโปรเซสย่อยต้องส่งโทเคนนี้ให้เคอร์เนลเพื่อยืนยันสิทธิ์
- สิ่งนี้ต่างจาก Unix ที่โปรเซสมีเพียงตัวระบุ และเคอร์เนลต้องติดตามในตารางโปรเซสว่าแต่ละโปรเซสทำอะไรได้บ้าง
ความเข้ากันได้
- เป้าหมายหลักของ NT คือเข้ากันได้กับแอปพลิเคชันที่เขียนมาสำหรับ Windows รุ่นเก่า, DOS, OS/2 และ POSIX
- เหตุผลหนึ่งเป็นเรื่องทางเทคนิค เพราะสิ่งนี้บังคับให้ระบบต้องมีการออกแบบที่สง่างาม
- อีกเหตุผลหนึ่งเป็นเรื่องทางการเมือง เพราะ NT ถูกพัฒนาร่วมกับ IBM และแม้ท้ายที่สุด NT จะกลายเป็น Windows แต่ก็ จำเป็นต้อง รองรับแอปพลิเคชัน OS/2
- ความจำเป็นด้านความเข้ากันได้นี้ทำให้การออกแบบของ NT แตกต่างจาก Unix อย่างมาก
- ใน Unix แอปพลิเคชันใน user space สื่อสารกับเคอร์เนลโดยตรงผ่านอินเทอร์เฟซ system call และอินเทอร์เฟซนี้ก็คืออินเทอร์เฟซแบบ Unix
- C library ทำหน้าที่เป็นตัวเชื่อมสำหรับเรียกเคอร์เนล และแอปพลิเคชันไม่ได้รัน system call โดยตรง แต่รายละเอียดนี้เป็นเพียงเรื่องเล็กน้อย
- ใน NT แอปพลิเคชัน ไม่ได้ สื่อสารกับ executive (เคอร์เนล) โดยตรง
- แต่แอปพลิเคชันแต่ละตัวจะสื่อสารกับ subsystem ที่ได้รับการป้องกันตัวใดตัวหนึ่ง ซึ่ง subsystem เหล่านี้ทำหน้าที่ติดตั้งใช้งาน API ของระบบปฏิบัติการต่าง ๆ ที่ NT ต้องการให้เข้ากันได้
- subsystem เหล่านี้ถูกติดตั้งเป็นเซิร์ฟเวอร์ใน user space (ไม่ได้อยู่ภายใน "microkernel" ของ NT)
- การรองรับแอปพลิเคชัน Windows มีให้ผ่าน Win32 server ซึ่งพิเศษเพราะเป็นเซิร์ฟเวอร์เพียงตัวเดียวที่ผู้ใช้มองเห็นได้โดยตรง: มันควบคุมโปรแกรมคอนโซลและเทอร์มินัล DOS และมีสิทธิพิเศษบางอย่างด้วยเหตุผลด้านประสิทธิภาพ
- เมื่อเทียบกับ Unix แบบดั้งเดิม BSD และ Linux มีเคอร์เนลแบบ monolithic ดังนั้นการออกแบบของ NT จึงต่างออกไปมาก
- เคอร์เนลเหล่านี้เปิดเผยอินเทอร์เฟซ system call ที่แอปพลิเคชันใน user space ใช้เพื่อโต้ตอบกับระบบโดยตรง
- อย่างไรก็ตาม BSD รองรับการรัน ไบนารี ทางเลือกภายในเคอร์เนลแบบ monolithic มายาวนาน: วิธีทำงานคือเปิดเผยตาราง system call ที่ต่างออกไปให้กับ user space ตามไบนารีที่กำลังรัน จากนั้นแปลง system call "ภายนอก" เหล่านั้นให้เป็นสิ่งที่เคอร์เนลเข้าใจ
- Linux ก็มีการรองรับแบบจำกัดสำหรับสิ่งนี้ผ่าน personalities เช่นกัน
- แม้แนวทางของ BSD จะแตกต่างจากวิธีที่ NT รองรับระบบอื่นมาก แต่ WSL 1 กลับคล้ายกันมาก และไม่ใช่ subsystem ตามคำจำกัดความดั้งเดิม
- ใน WSL 1 เคอร์เนล NT จะทำเครื่องหมายโปรเซส Linux เป็น pico process และจากจุดนั้นก็เปิดเผยอินเทอร์เฟซ system call แบบอื่นออกมา
- ภายในเคอร์เนล NT system call ที่เกี่ยวข้องกับ Linux เหล่านั้นจะถูกแปลงเป็นการทำงานของ NT และให้บริการภายในเคอร์เนลเดียวกัน คล้ายกับ Linux compatibility ของ BSD
- ปัญหาเดียวคือ NT ไม่ใช่ Unix ดังนั้นการ "จำลอง" Linux จึงทำได้ยากและช้ากว่าสิ่งที่ BSD สามารถให้ได้มาก
- น่าเสียดายที่ WSL 2 สูญเสียแก่นของการออกแบบนี้ไปและหันไปใช้การออกแบบแบบ VM เต็มรูปแบบ
- รายละเอียดที่น่าสนใจของการออกแบบ NT
- เป้าหมายของการออกแบบ NT คือเปิดทางให้มีการเปลี่ยนทาง I/O ระหว่าง subsystem ได้อย่างราบรื่นจากเชลล์เดียว
- subsystem จะถูกเปิดเผยให้แอปพลิเคชันผ่าน ports ซึ่งเป็นอ็อบเจ็กต์ของ NT และคล้ายกับวิธีที่ Mach ใช้ให้โปรเซสกับเซิร์ฟเวอร์สื่อสารกัน
หน่วยความจำเสมือน
- NT เช่นเดียวกับ Unix พึ่งพา Memory Management Unit(MMU) ที่มีการแบ่งหน้าเพื่อให้การปกป้องระหว่างโปรเซสและมอบหน่วยความจำเสมือน
- การแบ่งหน้าสำหรับโปรเซสใน user space เป็นกลไกทั่วไปที่ทำให้มีแอดเดรสสเปซใหญ่กว่าปริมาณหน่วยความจำจริงของเครื่อง
- อย่างไรก็ตาม สิ่งหนึ่งที่ทำให้ NT ล้ำหน้ากว่าระบบ Unix ร่วมยุคคือเคอร์เนลเองก็สามารถถูกเพจออกไปยังดิสก์ได้
- หากทั้งเคอร์เนลสามารถถูกเพจได้ทั้งหมด ก็อาจเกิดสถานการณ์ที่ต้องแก้ kernel page fault ซึ่งต้องใช้โค้ดของไดรเวอร์ระบบไฟล์ที่ถูกเพจออกไปแล้ว แต่ส่วนสำคัญของเคอร์เนลนั้นเพจได้
- ทุกวันนี้สิ่งนี้อาจไม่ได้น่าสนใจเป็นพิเศษ เพราะเคอร์เนลมีขนาดเล็กเมื่อเทียบกับหน่วยความจำที่ติดตั้งทั่วไปในเครื่อง แต่ในอดีตทุกไบต์มีค่า จึงสร้างความแตกต่างได้มาก
- ทุกวันนี้เราอาจมองว่าหน่วยความจำเสมือนและการแบ่งหน้าเป็นเรื่องปกติ แต่ตอนที่ NT ถูกออกแบบ นี่เป็นหัวข้อวิจัยขนาดใหญ่
- การติดตั้งใช้งาน Unix ก่อนหน้านั้นมีแคชหน่วยความจำแยกกันสำหรับระบบไฟล์และหน่วยความจำเสมือน และต้องรอถึงปี 1987 กว่า SunOS จะติดตั้งสถาปัตยกรรมหน่วยความจำเสมือนแบบรวมเพื่อลดโอเวอร์เฮดของการออกแบบเดิม
- ในทางกลับกัน NT เริ่มต้นมาพร้อมสถาปัตยกรรมหน่วยความจำแบบรวมตั้งแต่แรก
- อาจพูดได้ว่าการทำเช่นนี้ง่ายขึ้นเพราะมีข้อมูลเชิงลึกเกี่ยวกับความไม่มีประสิทธิภาพที่พบใน Unix และได้เห็นโซลูชันที่ SunOS ติดตั้งไว้ก่อนที่การออกแบบ NT จะเริ่มขึ้น
- แต่ก็ควรสังเกตว่าสิ่งนี้ทำให้ NT "ก้าวหน้ากว่า" ระบบปฏิบัติการอื่นจำนวนมากในเวลานั้น และระบบอื่น ๆ ก็เพิ่งตามทันในปี 2002 ด้วยการติดตั้ง Unified Buffer Cache(UBC) ของ NetBSD 1.6
- ความแตกต่างที่น่าสนใจระหว่าง NT กับ Unix คือวิธีจัดการและแสดงหน่วยความจำที่ใช้ร่วมกัน
- ใน NT ส่วนของหน่วยความจำที่ใช้ร่วมกันเป็นอ็อบเจ็กต์ จึงได้รับการตรวจสอบความถูกต้องของการเข้าถึงแบบเดียวกับอ็อบเจ็กต์อื่นทั้งหมด
- นอกจากนี้ยังเป็นส่วนหนึ่งของต้นไม้อ็อบเจ็กต์เดียว จึงสามารถระบุที่อยู่ได้ในลักษณะเดียวกับอ็อบเจ็กต์อื่นทั้งหมด
- ใน Unix ความสามารถนี้เป็นสิ่งที่ถูกยึดติดเพิ่มเข้าไปภายหลัง: อ็อบเจ็กต์หน่วยความจำที่ใช้ร่วมกันมีเนมสเปซแยก มี API แยกจากเอนทิตีอื่นทั้งหมด ดังนั้นสิทธิ์แบบทั่วไปจึงไม่ถูกนำมาใช้
ระบบย่อย I/O
- Unix รุ่นแรก ๆ รองรับระบบไฟล์ได้เพียงระบบเดียว
- ตัวอย่างเช่น BSD ได้รับ abstraction ของ Virtual File System(VFS) เพื่อรองรับมากกว่า UFS ก็ต้องรอถึง 4.3BSD ในเดือนเมษายน 1990
- ในทางกลับกัน NT เริ่มต้นจากการออกแบบที่รองรับหลายระบบไฟล์
- เพื่อรองรับหลายระบบไฟล์ เคอร์เนลจำเป็นต้องเปิดเผย namespace ของระบบเหล่านั้นไม่ทางใดก็ทางหนึ่ง
- Unix รวมระบบไฟล์เข้าด้วยกันในลำดับชั้นไฟล์เดียวผ่าน mount point: เลเยอร์ VFS มีกลไกสำหรับระบุโหนดที่สอดคล้องกับรากของระบบไฟล์ และเปลี่ยนเส้นทางคำขอไปยังไดรเวอร์ระบบไฟล์นั้นเมื่อมีการไล่ตาม path
- NT มีการออกแบบคล้ายกัน แม้ในส่วนติดต่อผู้ใช้มาตรฐานระบบไฟล์จะปรากฏเป็นไดรฟ์ที่แยกจากกัน: ภายในแล้ว executive จะแทนระบบไฟล์เป็นอ็อบเจ็กต์ใน object tree และแต่ละอ็อบเจ็กต์มีหน้าที่แยกวิเคราะห์ส่วนที่เหลือของ path
- จากนั้นอ็อบเจ็กต์ระบบไฟล์เหล่านั้นจะถูกแมปกลับเป็นไดรฟ์ DOS เพื่อให้เข้าถึงได้จาก user space
- ไดรฟ์ DOS เองก็เป็นอ็อบเจ็กต์ภายใต้ subtree แยกต่างหากที่ทำหน้าที่ redirect I/O ไปยังระบบไฟล์ที่อ้างถึง
- ในท้ายที่สุด NT เปิดตัวพร้อมกับ NTFS
- แม้ NTFS จะชอบถูกโจมตีว่าให้ประสิทธิภาพไม่ดี (ซึ่งเป็นข้อกล่าวหาที่ไม่ถูกต้อง) แต่มันเป็นระบบไฟล์ที่ก้าวหน้ามากสำหรับยุคนั้น
- ระบบย่อย I/O ของ NT เมื่อทำงานร่วมกับ NTFS ได้มอบการอ้างแอดเดรสแบบ 64 บิต, journaling และแม้กระทั่งชื่อไฟล์แบบ Unicode
- Linux ยังไม่ได้รองรับไฟล์ 64 บิตจนถึงช่วงปลายทศวรรษ 1990 และยังไม่มี journaling จนกว่า ext3 จะเปิดตัวในปี 2001
- Soft updates ซึ่งเป็นกลไกด้าน fault tolerance ทางเลือก เพิ่งปรากฏใน FreeBSD ในปี 1998
- Unix แทนชื่อไฟล์เป็นอาร์เรย์ไบต์ที่ลงท้ายด้วย null ไม่ใช่ Unicode
- ฟีเจอร์อื่นที่มีมาในตอนเปิดตัว NT ได้แก่ disk striping และ mirroring (สิ่งที่ปัจจุบันเรียกว่า RAID) รวมถึงการ hot-plug อุปกรณ์
- ฟีเจอร์เหล่านี้ไม่ใช่ของใหม่ เพราะ SunOS มี RAID รองรับมาตั้งแต่ต้นทศวรรษ 1990 แต่จุดที่น่าสนใจคือทั้งหมดนี้ถูกพิจารณาไว้เป็นส่วนหนึ่งของการออกแบบตั้งแต่แรก
- ในระดับที่สูงขึ้น สิ่งที่ทำให้ระบบย่อย I/O ของ NT ก้าวหน้ากว่า Unix มากคืออินเทอร์เฟซของมันมีลักษณะเป็น asynchronous โดยเนื้อแท้ และเป็นเช่นนั้นมาตั้งแต่ต้น
- เพื่อให้เห็นภาพ FreeBSD เพิ่งมีการรองรับ aio(7) ใน FreeBSD 3.0 ปี 1998 และ Linux ก็เพิ่งมีใน Linux 2.5 ปี 2002
- แม้ระบบ Unix จะมีการรองรับ asynchronous I/O มานานกว่า 20 ปีแล้ว แต่มันก็ยังไม่ถูกใช้อย่างแพร่หลาย: แทบไม่มีใครรู้จัก API เหล่านี้ แอปพลิเคชันส่วนใหญ่ก็ไม่ใช้ และประสิทธิภาพก็ไม่ดี
- io_uring ของ Linux เป็นส่วนเสริมที่ค่อนข้างใหม่เพื่อปรับปรุง asynchronous I/O แต่ก็เป็นสาเหตุสำคัญของช่องโหว่ด้านความปลอดภัยและยังไม่ถูกใช้อย่างแพร่หลาย
เครือข่าย
- ทุกวันนี้อินเทอร์เน็ตมีอยู่ทุกหนแห่ง แต่ตอนที่ NT ถูกออกแบบนั้นยังไม่เป็นเช่นนั้น
- หากมองย้อนกลับไปใน ecosystem ของ Microsoft, DOS 3.1 (1987) มีพื้นฐานสำหรับการแชร์ไฟล์บนระบบไฟล์ FAT แล้ว แต่ตัว "OS" เองไม่ได้มีความสามารถด้านเครือข่าย: มีผลิตภัณฑ์แยกต่างหากชื่อ Microsoft Networks(MS-NET) ที่ทำหน้าที่นี้
- Windows 3.0 (1990) มีการรองรับ NetBIOS ที่เปิดให้มีการแชร์พรินเตอร์และไฟล์พื้นฐานบนเครือข่ายท้องถิ่น แต่ยังไม่พบการรองรับ TCP/IP
- ในทางกลับกัน Unix คืออินเทอร์เน็ตนั่นเอง: โปรโตคอลอินเทอร์เน็ตพื้นฐานทั้งหมดถูกเขียนบน Unix และเขียนขึ้นเพื่อ Unix
- ระหว่างการออกแบบ NT การคำนึงถึงการรองรับเครือข่ายที่ดีจึงเป็นเรื่องสำคัญ และท้ายที่สุด NT ก็เปิดตัวพร้อมความสามารถด้านเครือข่าย
- ผลลัพธ์คือ NT รองรับทั้งโปรโตคอลอินเทอร์เน็ตและโปรโตคอล LAN แบบดั้งเดิมที่ใช้ในสภาพแวดล้อม Microsoft เดิม ซึ่งทำให้ NT เหนือกว่า Unix ในสภาพแวดล้อมองค์กร
- ตัวอย่างหนึ่งคือ network domain ของ NT
- ใน Unix ผู้ดูแลเครือข่ายโดยทั่วไปมักซิงก์บัญชีผู้ใช้ระหว่างเครื่องต่าง ๆ ด้วยตนเอง
- ระบบอย่าง SunOS อาจใช้โปรโตคอลไดเรกทอรี X.500 (1988) และ Kerberos (ทศวรรษ 1980) สำหรับการยืนยันตัวตนผู้ใช้ แต่เทคโนโลยีเหล่านี้ไม่ได้เรียบง่ายเป็นพิเศษ
- แทนที่จะเป็นเช่นนั้น NT ให้ domain ที่รวมฟังก์ชันไดเรกทอรีและการยืนยันตัวตนมาตั้งแต่เริ่ม ซึ่งดูเหมือนจะเป็นสิ่งที่ "ชนะ" ในเครือข่ายองค์กร เพราะตั้งค่าได้ง่ายกว่ามากและมีมาในระบบอยู่แล้ว
- เป้าหมายของการซิงก์บัญชีผู้ใช้คือการแชร์ทรัพยากรระหว่างเครื่อง โดยหลักคือไฟล์ และเมื่อทำเช่นนี้ วิธีการแสดงสิทธิ์ก็มีความสำคัญ
- เป็นเวลานาน Unix ให้เพียงชุดสิทธิ์อ่าน/เขียน/รันอย่างง่ายสำหรับแต่ละไฟล์
- ในทางกลับกัน NT มาพร้อม ACL ขั้นสูงตั้งแต่แรก ซึ่งยังคงเป็นจุดเจ็บปวดของ Unix มาจนถึงทุกวันนี้
- แม้ตอนนี้ Linux และ BSD ก็มี ACL แล้ว แต่ส่วนติดต่อระหว่างระบบไม่สอดคล้องกัน และให้ความรู้สึกเหมือนเป็นส่วนเสริมที่แปลกแยกกับการออกแบบระบบ
- ใน NT, ACL ทำงานในระดับอ็อบเจ็กต์ จึงถูกนำไปใช้อย่างสอดคล้องกับความสามารถทั้งหมดของเคอร์เนล
- เมื่อพูดถึงการแชร์ไฟล์ ก็ต้องพูดถึง network file system
- ในโลก Unix นั้นโดยพฤตินัยระบบไฟล์คือ NFS และใน NT คือ SMB
- SMB สืบทอดมาจาก MS-NET และ LAN Manager และถูกทำให้เป็นจริงในเคอร์เนลผ่านคอมโพเนนต์ที่เรียกว่า redirector
- โดยเนื้อแท้แล้ว redirector ก็เป็นอีกระบบไฟล์หนึ่งที่ "เรียบง่าย" ทำหน้าที่ดักจับการทำงานกับไฟล์และส่งต่อผ่านเครือข่าย เช่นเดียวกับที่ NFS เป็นอยู่ใน Unix
- protobuf และ gRPC อาจถูกใช้กันแพร่หลายจนดูเหมือนเป็นไอเดียใหม่ แต่จริง ๆ แล้วตั้งอยู่บนแนวคิดเก่า
- ใน Unix มีการใช้ Sun RPC มาตั้งแต่ต้นทศวรรษ 1980 โดยหลักเพื่อรองรับ NFS
- เช่นเดียวกัน NT ก็มาพร้อมการรองรับ RPC ในตัว ผ่าน DSL ของตัวเอง (ซึ่งรู้จักกันในชื่อ MIDL สำหรับระบุ interface definition และสร้างโค้ดสำหรับ remote procedure) รวมถึงความสามารถของตัวเองสำหรับการสร้าง RPC client และ server
- ระบบ Unix ไม่ได้มุ่งเน้นอย่างหนักไปที่การรองรับไดรเวอร์ตามอำเภอใจ: โดยทั่วไปแล้วระบบ Unix มักผูกติดกับเครื่องและผู้ขายเฉพาะราย
- ในทางกลับกัน NT พยายามจะเป็น OS สำหรับ "ทุก" เครื่อง และถูกขายโดยบริษัทซอฟต์แวร์ ดังนั้นการรองรับไดรเวอร์ที่ผู้อื่นเขียนจึงสำคัญ
- ผลก็คือ NT มาพร้อม Network Driver Interface Specification(NDIS) ซึ่งเป็น abstraction เพื่อให้รองรับไดรเวอร์การ์ดเครือข่ายได้ง่าย
- จนถึงทุกวันนี้ ไดรเวอร์ที่ผู้ผลิตจัดหาให้ก็ยังไม่ใช่เรื่องปกตินักบน Linux และสิ่งนี้นำไปสู่อุปกรณ์/กลไกที่น่าสนใจอย่าง ndiswrapper ซึ่งเคยได้รับความนิยมมากในช่วงต้นทศวรรษ 2000 เพราะทำให้สามารถนำไดรเวอร์ Windows สำหรับการ์ด WiFi มาใช้ซ้ำบน Linux ได้
- สุดท้าย ความแตกต่างอีกอย่างระหว่าง NT กับ Unix อยู่ที่การทำงานของ named pipe
- named pipe ใน Unix เป็นองค์ประกอบภายในเครื่อง: มันมอบกลไกให้สองโปรเซสบนเครื่องเดียวกันสื่อสารกันได้ผ่านชื่อไฟล์แบบถาวรบนดิสก์
- NT ก็มีความสามารถเดียวกันนี้ แต่ named pipe สามารถทำงานผ่านเครือข่ายได้
- หากวาง named pipe ไว้บนระบบไฟล์ที่แชร์อยู่ แอปพลิเคชันสองตัวบนคอมพิวเตอร์ต่างกันก็สามารถสื่อสารกันได้โดยไม่ต้องกังวลกับรายละเอียดด้านเครือข่าย
User-Space
- การตั้งค่า:
- NT รวมการตั้งค่าระบบและแอปพลิเคชันไว้ศูนย์กลางในฐานข้อมูลที่เรียกว่า Registry ทำให้หลุดพ้นจาก CONFIG.SYS, AUTOEXEC.BAT และไฟล์ INI จำนวนมากที่ใช้ใน Windows รุ่นเก่า
- แม้สิ่งนี้จะทำให้บางคนไม่พอใจอย่างมาก แต่ท้ายที่สุดอินเทอร์เฟซการตั้งค่าแบบรวมศูนย์ก็เป็นประโยชน์ต่อทุกฝ่าย: การเขียนแอปทำได้ง่ายขึ้นเพราะมีพื้นฐานให้รองรับเพียงแบบเดียว และผู้ใช้ก็ปรับแต่งระบบได้ง่ายขึ้นเพราะมีที่ให้ตรวจดูเพียงแห่งเดียว
- ในทางกลับกัน Unix ยังคงมีปัญหาจาก DSL หลายสิบแบบและตำแหน่งไฟล์ที่ไม่สอดคล้องกัน
- แต่ละโปรแกรมที่รองรับไฟล์คอนฟิกก็มีไวยากรณ์ของตัวเอง และการรู้ว่าโปรแกรมอ่านจากที่ใดก็เป็นเรื่องยาก แถมยังไม่ได้มีเอกสารอธิบายไว้อย่างดีเสมอไป
- ระบบนิเวศ Linux พยายามผลักดันแนวทางคล้าย NT ผ่าน XDG และ dconf (เดิมคือ GConf) แต่ส่วนประกอบฝั่งเดสก์ท็อปใช้เทคโนโลยีเหล่านี้แบบเฉพาะทาง ขณะที่ส่วนประกอบหลักของระบบกลับไม่รับไปใช้ จึงทิ้งความไม่สอดคล้องกันที่ยุ่งเหยิงไว้
- การทำให้รองรับหลายภาษา:
- Microsoft ในฐานะบริษัทขนาดใหญ่ที่นำ Windows 3.x ออกวางจำหน่ายทั่วโลกอยู่แล้ว เข้าใจว่าการแปลและปรับให้เข้าท้องถิ่นมีความสำคัญ และจึงทำให้ NT รองรับความสามารถเหล่านี้มาตั้งแต่ต้น
- เมื่อนำไปเทียบกับ Unix ซึ่งการรองรับ UTF เริ่มปรากฏขึ้นในช่วงปลายทศวรรษ 1990 และรองรับภาษาอื่นผ่านส่วนเสริม gettext แบบเลือกติดตั้ง จะเห็นความต่างได้ชัดเจน
- ภาษา C:
- สิ่งหนึ่งที่ระบบ Unix อย่าง FreeBSD และ NetBSD ใฝ่ฝันกันมาระยะหนึ่งคือการคิดค้นสำเนียง C ของตนเองขึ้นมาเพื่อใช้เขียนเคอร์เนลให้ปลอดภัยยิ่งขึ้น
- แต่แนวทางนี้ก็ไม่ไปถึงไหน ยกเว้น Linux ที่พึ่งพาส่วนขยายเฉพาะของ GCC
- ขณะที่ Microsoft มีข้อได้เปรียบจากการเป็นเจ้าของคอมไพเลอร์ C จึงทำสิ่งนี้ได้ใน NT ที่เขียนด้วย Microsoft C
- ตัวอย่างเช่น NT พึ่งพา Structured Exception Handling (SEH) ซึ่งเป็นความสามารถในการเพิ่ม clause
try/except เพื่อจัดการข้อยกเว้นทั้งจากซอฟต์แวร์และฮาร์ดแวร์
- คงพูดไม่ได้ว่านี่เป็นข้อได้เปรียบใหญ่โต แต่ก็เป็นความแตกต่างที่มีอยู่จริง
บทสรุป
- NT เป็นเทคโนโลยีที่ก้าวล้ำในช่วงเวลาที่เปิดตัว
- ดังที่อธิบายไว้ข้างต้น ฟีเจอร์จำนวนมากที่ทุกวันนี้เรามองว่าเป็นเรื่องปกติของการออกแบบระบบ มีอยู่ใน NT มาตั้งแต่แรก ขณะที่ระบบ Unix อื่นแทบทั้งหมดต้องค่อย ๆ เพิ่มความสามารถเหล่านั้นเข้ามาเมื่อเวลาผ่านไป
- ผลก็คือ ฟีเจอร์เหล่านี้ไม่ได้ผสานเข้ากับปรัชญา Unix ได้อย่างราบรื่นเสมอไป
- อย่างไรก็ตาม ทุกวันนี้ยังไม่ชัดเจนนักว่า NT "ก้าวหน้ากว่า" Linux หรือ FreeBSD อย่างแท้จริงหรือไม่
- NT มีหลักการออกแบบที่แข็งแรงกว่าและมีฟีเจอร์มากกว่าระบบปฏิบัติการร่วมยุคตั้งแต่แรกเริ่ม แต่ในปัจจุบันความแตกต่างกลับเลือนราง
- กล่าวคือ NT มีพัฒนาการขึ้น แต่ไม่ได้ก้าวหน้ากว่า Unix สมัยใหม่อย่างมีนัยสำคัญนัก
- แม้ NT จะมีหลักการออกแบบที่แข็งแรงทั้งหมดนี้อยู่ แต่ก็น่าเสียดายที่การบวมพองของ UI ทำให้การออกแบบเหล่านี้ไม่สามารถเปล่งประกายได้
- แม้บนเครื่องที่แรงมาก ความช้าของ OS ก็อาจทำให้ดูแล้วทรมาน และอาจถึงขั้นนำไปสู่จุดจบของ OS นี้ได้
สรุปโดย GN⁺
- บทความนี้เปรียบเทียบความแตกต่างด้านการออกแบบระหว่าง NT กับ Unix เพื่ออธิบายว่าการออกแบบยุคแรกของ NT มีความล้ำหน้าเพียงใด
- NT ถูกออกแบบมาตั้งแต่ต้นโดยมีเป้าหมายด้านการพกพาข้ามแพลตฟอร์ม การรองรับมัลติโปรเซสซิง และความเข้ากันได้ ซึ่งเป็นความต่างสำคัญจาก Unix
- เคอร์เนลเชิงวัตถุ สถาปัตยกรรมหน่วยความจำแบบรวม และอินเทอร์เฟซ I/O แบบอะซิงโครนัสของ NT ล้วนมอบความสามารถที่ก้าวหน้ากว่า Unix
- อย่างไรก็ตาม ในปัจจุบันความแตกต่างระหว่างระบบ NT และ Unix ไม่ได้มากนัก และความเทอะทะของ UI ใน NT ก็ทำให้ประสิทธิภาพลดลง
1 ความคิดเห็น
ความเห็นจาก Hacker News
เคอร์เนล NT นั้นยอดเยี่ยม แต่เป็นการออกแบบที่เก่าแล้ว
ความแตกต่างที่ใหญ่ที่สุดระหว่าง NT กับ Unix คือแนวทางการเข้าถึงไดรเวอร์
ใน WinNT ยุคใหม่ Direct3D เป็นส่วนที่จำเป็นของเคอร์เนล
เคอร์เนล NT รันเธรด ไม่ใช่โปรเซส
ในช่วงแรก WindowsNT เป็นระบบที่ออกแบบมาดีกว่า Linux อย่างมาก
NT ในฐานะระบบที่สาม สามารถหลีกเลี่ยง second-system syndrome ได้
จากมุมมองของนักพัฒนา มีความแตกต่างระหว่าง Windows กับ Linux
wchar_tใน Win32 เป็นปัญหาเคอร์เนล NT มีความงดงาม แต่ไม่ใช่โอเพนซอร์ส
มีการผสานแนวคิดแบบเดียวกับ FUSE ของ Linux