الدرس 6: fork() — إنشاء عملية ابنة
fork() هو الـ syscall الذي يضاعف عدد العمليات: فهو ينشئ نسخة مطابقة تماماً من العملية الحالية. فهم fork() ضروري لكل مهندس أنظمة — إذ يستخدمه nvidia-docker ومخصِّص GPU في Slurm لإنشاء بيئات معزولة لكل مهمة GPU. وعندما يحدث خطأ ما مع عمليات GPU، تكون معرفة fork() أول أداة تشخيص.
fork() أشبه بتصوير كل محتويات دماغك ووضعها في جسد آخر — وفجأة يصبح هناك شخصان يتذكران كل شيء حتى لحظة النسخ. الفرق الوحيد هو أن أحدهما يحمل رقم ID مختلفاً عن الآخر.
- fork()
- syscall ينشئ عملية ابنة تكون نسخة من العملية الأب. يُرجِع fork() القيمة 0 للابن، وPID الابن للأب، و-1 إذا فشل.
- Copy-on-Write (COW)
- تحسينٌ لعمل fork(): لا ينسخ الـ kernel كل الذاكرة فعلياً على الفور. تُشارَك صفحات الذاكرة مع الأب حتى تكتب إحدى العمليتين — وعندئذٍ تُنسَخ تلك الصفحة فقط.
- عملية ابنة
- عملية يتم إنشاؤها بواسطة fork(). يحصل الابن على PID جديد، لكن الـ PPID الخاص به هو PID الأب. للابن نسخة مستقلة من مساحة العناوين.
- getpid() / getppid()
- syscalls تُرجِع PID العملية الحالية وPID الأب الخاص بها على التوالي. مفيدة بعد fork() للتمييز بين الأب والابن.
- تكرار مساحة العناوين
- ينشئ fork() للابن مساحة عناوين افتراضية مستقلة بالعناوين نفسها التي للأب. تغيير متغير في الابن لا يؤثر على الأب والعكس صحيح (بفضل Copy-on-Write).