١ مقدمة في أنظمة التشغيل
🎯 وش هو نظام التشغيل؟
تعريف: برنامج يشتغل كوسيط بين المستخدمين وعتاد الكمبيوتر.
- الأهداف: تنفيذ برامج المستخدم، تسهيل استخدام النظام، استغلال العتاد بكفاءة
- النواة (Kernel): البرنامج الوحيد اللي دايمًا شغال على الكمبيوتر (جوهر نظام التشغيل)
تذكر المكونات الأربعة: العتاد → نظام التشغيل → التطبيقات → المستخدمين
💾 تنظيم نظام الكمبيوتر
| المكون | وقت الوصول | تطاير |
|---|---|---|
| المسجلات | ~١ نانوثانية | متطايرة |
| الذاكرة المخبئية | ~٢-١٠ نانوثانية | متطايرة |
| الذاكرة الرئيسية (RAM) | ~١٠٠ نانوثانية | متطايرة |
| SSD | ~١٠٠ ميكروثانية | غير متطايرة |
| القرص الصلب | ~٨-٥٠ ملي ثانية | غير متطايرة |
اختصار: "RegistersCacheRAM" → RCR → أسرع وأغلى
⚡ المقاطعات
الأنواع:
- مقاطعة عتادية: من أجهزة الإدخال/الإخراج (كيبورد، فأرة، قرص)
- مقاطعة برمجية (Trap/Exception): من أخطاء أو استدعاءات نظام
عملية معالجة المقاطعة:
- حفظ PCB (عداد البرنامج والمسجلات)
- تحديد نوع المقاطعة (polling أو vectored)
- تنفيذ روتين خدمة المقاطعة (ISR)
- استعادة المعلومات المحفوظة
- استئناف التنفيذ
متجه المقاطعة = جدول عناوين يشير إلى روتينات خدمة المقاطعة
🚀 DMA (الوصول المباشر للذاكرة)
- يستخدم لأجهزة الإدخال/الإخراج عالية السرعة
- ينقل البيانات مباشرة بين الإدخال/الإخراج والذاكرة بدون المعالج
- مقاطعة واحدة فقط لكل كتلة (مو لكل بايت)
سؤال: وش هو الأفضل لنقل كميات كبيرة من البيانات بين أجهزة الإدخال/الإخراج والذاكرة الرئيسية بدون تدخل المعالج؟
الجواب: DMA
الجواب: DMA
🖥️ أنظمة متعددة المعالجات
متماثلة (SMP)
- كل معالج يؤدي كل المهام
- مافي علاقة رئيسي-تابع
- معالجات متساوية
غير متماثلة (AMP)
- معالج رئيسي يتحكم في التابعين
- علاقة مدير-موظف
- تستخدم في الأنظمة الكبيرة
المزايا:
- زيادة الإنتاجية: شغل أكثر بوقت أقل
- اقتصاد الحجم: تكلفة أقل من عدة أنظمة أحادية المعالج
- زيادة الموثوقية: التدهور التدريجي/تحمل الأخطاء
🔐 التشغيل ثنائي الوضع
| الوضع | قيمة البت | الغرض |
|---|---|---|
| وضع النواة/النظام | ٠ | تنفيذ نظام التشغيل، تعليمات مميزة |
| وضع المستخدم | ١ | تنفيذ تطبيقات المستخدم |
استدعاء النظام يغيّر الوضع إلى نواة، والرجوع يعيده لوضع المستخدم
سؤال: التعليمات المميزة يمكن تنفيذها فقط في؟
الجواب: وضع النواة (mode bit = ٠)
الجواب: وضع النواة (mode bit = ٠)
٢ هياكل أنظمة التشغيل
🛠️ خدمات نظام التشغيل
للمستخدمين:
- واجهة المستخدم: CLI، GUI، شاشة لمس
- تنفيذ البرامج: تحميل، تشغيل، إنهاء البرامج
- عمليات الإدخال/الإخراج: المستخدمون لا يستطيعون تنفيذ I/O مباشرة
- التعامل مع نظام الملفات: قراءة، كتابة، إنشاء، حذف
- الاتصالات: ذاكرة مشتركة أو تمرير رسائل
- اكتشاف الأخطاء: كشف أخطاء المعالج، الذاكرة، الإدخال/الإخراج
لكفاءة النظام:
- تخصيص الموارد: إدارة المعالج، الذاكرة، الملفات
- المحاسبة: تتبع إحصائيات الاستخدام
- الحماية والأمان: التحكم في الوصول، الدفاع ضد الهجمات
📞 استدعاءات النظام
تعريف: واجهة بين البرنامج الجاري ونظام التشغيل
- يُوصل إليها عبر API (Win32, POSIX, Java)
- كل استدعاء نظام له رقم
- واجهة استدعاء النظام تحتفظ بجدول مفهرس
طرق تمرير المعاملات:
- المسجلات: أبسط، محدود بعدد المسجلات
- كتلة/جدول في الذاكرة: تمرير عنوان الكتلة
- المكدس: دفع المعاملات، سحبها بواسطة نظام التشغيل
| الفئة | أمثلة |
|---|---|
| التحكم في العمليات | fork(), exec(), exit(), wait() |
| إدارة الملفات | open(), close(), read(), write() |
| إدارة الأجهزة | request(), release(), read(), write() |
| صيانة المعلومات | getpid(), time(), date() |
| الاتصالات | send(), receive(), create/delete connection |
🏗️ أنواع هيكلة نظام التشغيل
١. أحادي النواة (هيكل بسيط - MS-DOS)
- كل الوظائف في ملف واحد
- سريع لكن صعب الصيانة
- التغييرات تؤثر على النظام كله
٢. الهيكلة الطبقية
- الطبقة ٠ = العتاد، الطبقة N = واجهة المستخدم
- كل طبقة تستخدم فقط الطبقات الأدنى
- سهلة التصحيح لكن عبء أداء
٣. النواة المصغرة
- نقل المكونات غير الأساسية إلى مساحة المستخدم
- الاتصال عبر تمرير الرسائل
- المزايا: سهلة التوسيع، قابلة للنقل، موثوقة، آمنة
- العيوب: عبء الاتصال
٤. الوحدات (النهج الحديث)
- نواة أساسية + وحدات قابلة للتحميل
- مشابهة للطبقات لكن أكثر مرونة
- تستخدم في لينكس، macOS، Solaris، ويندوز
سؤال: أي نهج يسمح بالتواصل المباشر بين كل خدمات نظام التشغيل؟
الجواب: النهج المعياري (أي وحدة يمكنها استدعاء أي وحدة أخرى)
الجواب: النهج المعياري (أي وحدة يمكنها استدعاء أي وحدة أخرى)
٣ العمليات
📋 مفهوم العملية
العملية = برنامج قيد التنفيذ
- البرنامج: كيان خامل (ملف تنفيذي على القرص)
- العملية: كيان نشط (برنامج محمّل في الذاكرة)
توزيع الذاكرة للعملية:
- قسم النص: كود البرنامج (للقراءة فقط)
- قسم البيانات: المتغيرات العامة
- الكومة: ذاكرة تُخصص ديناميكيًا (تنمو للأعلى)
- المكدس: معاملات الدوال، عناوين العودة، متغيرات محلية (ينمو للأسفل)
تذكر: "نص بيانات كومة مكدس" → من العناوين المنخفضة للعالية
🔄 حالات العملية
مخطط حالة العملية:
جديدة → [قبول] → جاهزة → [توزيع المجدول] → قيد التشغيل
↑_____________←_[اكتمال I/O]_←_منتظرة_←_[انتظار I/O]_←_↓
قيد التشغيل → [مقاطعة] → جاهزة
قيد التشغيل → [خروج] → منتهية
جديدة → [قبول] → جاهزة → [توزيع المجدول] → قيد التشغيل
↑_____________←_[اكتمال I/O]_←_منتظرة_←_[انتظار I/O]_←_↓
قيد التشغيل → [مقاطعة] → جاهزة
قيد التشغيل → [خروج] → منتهية
| الحالة | الوصف |
|---|---|
| جديدة | العملية قيد الإنشاء، يتم تهيئة PCB |
| جاهزة | تنتظر أن تُسند إلى معالج |
| قيد التشغيل | يتم تنفيذ التعليمات |
| منتظرة | تنتظر إدخال/إخراج أو حدث |
| منتهية | العملية أنهت تنفيذها |
سؤال: عملية في حالة قيد التشغيل يمكن أن تنتقل إلى أي حالات؟
الجواب: جاهزة، منتظرة، منتهية
الجواب: جاهزة، منتظرة، منتهية
📦 كتلة التحكم في العملية (PCB)
PCB يحتوي على:
- معرف العملية (PID)
- حالة العملية (جاهزة، قيد التشغيل، إلخ)
- عداد البرنامج (PC)
- مسجلات المعالج
- معلومات جدولة المعالج (أولوية، قوائم)
- معلومات إدارة الذاكرة
- معلومات المحاسبة (وقت المعالج، حدود الوقت)
- معلومات حالة الإدخال/الإخراج (ملفات مفتوحة، أجهزة)
PCB يُخزّن في ذاكرة النواة، مو في قسم النص للعملية
🔀 تبديل السياق
الخطوات:
- حفظ PCB للعملية الحالية (المسجلات، PC، الحالة)
- تحميل PCB للعملية الجديدة
- استئناف تنفيذ العملية الجديدة
وقت تبديل السياق:
- عبء خالص (مافي شغل مفيد أثناء التبديل)
- يعتمد على دعم العتاد (بعض المعالجات لديها مجموعات مسجلات متعددة)
- عادةً ١-١٠٠٠ ميكروثانية
📅 جدولة العمليات
| المجدول | اسم آخر | الغرض | التكرار |
|---|---|---|---|
| طويلة المدى | جدول الوظائف | اختيار أي وظائف تُحمل إلى قائمة الانتظار الجاهزة | غير متكرر (ثواني/دقائق) |
| قصيرة المدى | جدول المعالج | اختيار أي عملية جاهزة تحصل على المعالج | متكرر جدًا (أجزاء من الثانية) |
| متوسطة المدى | المبادل | مبادلة العمليات داخل/خارج الذاكرة | متوسط |
أنواع العمليات:
- مقيدة بالإدخال/الإخراج: وقت أكثر في I/O، انفجارات معالج قصيرة كثيرة
- مقيدة بالمعالج: وقت أكثر في الحساب، انفجارات معالج طويلة قليلة
المجدول طويل المدى يتحكم في درجة تعدد البرمجة
👶 إنشاء العمليات - fork()
استدعاء النظام fork():
- ينشئ عملية ابنة (نسخة من الأم)
- يرجع ٠ للعملية الابنة
- يرجع PID الابنة للعملية الأم
- يرجع -١ عند الخطأ
pid_t pid = fork();
if (pid < 0) {
// حدث خطأ
fprintf(stderr, "فشل Fork");
}
else if (pid == 0) {
// العملية الابنة
printf("أنا الابنة، pid = %d", getpid());
}
else {
// العملية الأم
printf("أنا الأم، pid ابنتي = %d", pid);
wait(NULL); // انتظار إنهاء الابنة
}
سؤال: باعتبار أن PIDs الفعلية هي الأم=٣٦٠٠، الابنة=٣٦٠٨:
السطر A (الابنة): pid = ٠
السطر B (الابنة): pid1 = ٣٦٠٨
السطر C (الأم): pid = ٣٦٠٨
السطر D (الأم): pid1 = ٣٦٠٠
السطر A (الابنة): pid = ٠
السطر B (الابنة): pid1 = ٣٦٠٨
السطر C (الأم): pid = ٣٦٠٨
السطر D (الأم): pid1 = ٣٦٠٠
سؤال: كم عملية تنشأ بأربع استدعاءات fork() في حلقة؟
الجواب: ٢^٤ = ١٦ عملية (بما في ذلك الأم)
الجواب: ٢^٤ = ١٦ عملية (بما في ذلك الأم)
الابنة تحصل على نسخة من ذاكرة الأم (البيانات، الكومة، المكدس)، مو مشتركة!
💬 الاتصال بين العمليات (IPC)
ذاكرة مشتركة
- أسرع - لا استدعاءات نظام بعد الإعداد
- وصول مباشر للذاكرة
- يحتاج مزامنة
- جيد للبيانات الكبيرة
تمرير رسائل
- أسهل - نظام التشغيل يتولى المزامنة
- استدعاءات نظام send() و receive()
- أبطأ بسبب استدعاءات النظام
- جيد للرسائل الصغيرة
٤ الخيوط والتزامن
🧵 أساسيات الخيوط
الخيط = عملية خفيفة الوزن
الخيط هو وحدة أساسية لاستغلال المعالج ويتكون من:
- معرف الخيط
- عداد البرنامج
- مجموعة المسجلات
- المكدس
الخيوط تشارك داخل العملية:
- قسم الكود
- قسم البيانات (المتغيرات العامة)
- الكومة
- الملفات المفتوحة
- موارد نظام التشغيل
كل خيط له خاصته:
- المكدس
- عداد البرنامج
- المسجلات
سؤال: أي مما يلي لا تشاركه الخيوط؟
الجواب: عداد البرنامج والمكدس
الجواب: عداد البرنامج والمكدس
✅ فوائد تعدد الخيوط
- الاستجابة: البرنامج يستمر حتى لو جزء منه محجوب (مثل متصفح ويب يحمل صورة والمستخدم يتفاعل)
- مشاركة الموارد: الخيوط تشارك الذاكرة والموارد (أسهل من IPC)
- الاقتصاد:
- إنشاء خيط: أسرع ٣٠ مرة من عملية (في Solaris)
- تبديل السياق بين الخيوط: أسرع
- قابلية التوسع: يستفيد من معماريات متعددة المعالجات
سؤال: ليش نستخدم خيوط بدل العمليات؟
الجواب: إنشاء أسرع، تبديل سياق أسرع، تواصل أسهل (ذاكرة مشتركة)
الجواب: إنشاء أسرع، تبديل سياق أسرع، تواصل أسهل (ذاكرة مشتركة)
🔗 نماذج تعدد الخيوط
١. متعدد إلى واحد
- خيوط مستخدم كثيرة → خيط نواة واحد
- تُدار بواسطة مكتبة الخيوط (فعالة)
- ❌ العملية بأكملها تُحجب إذا انحجب خيط واحد
- ❌ لا يمكن أن تعمل بالتوازي على معالجات متعددة
- مثال: Green Threads
٢. واحد إلى واحد
- كل خيط مستخدم → خيط نواة
- ✅ توازٍ أكبر (خيط ينحجب، الآخرون يعملون)
- ✅ يمكن أن تعمل بالتوازي على معالجات متعددة
- ❌ عبء إنشاء خيوط النواة
- مثال: ويندوز، لينكس
٣. متعدد إلى متعدد
- خيوط مستخدم كثيرة → خيوط نواة كثيرة
- ✅ أفضل الميزات من كلا النموذجين
- ✅ يمكن أن تعمل بالتوازي
- ✅ إذا انحجب خيط، يمكن جدولة آخر
- مثال: Solaris قبل الإصدار ٩
⚡ التزامن مقابل التوازي
التزامن
- مهام متعددة تتقدم
- تقاسم الوقت على نواة واحدة
- تنفيذ متداخل
التوازي
- مهام متعددة تُنفذ في وقت واحد
- يحتاج نوى متعددة
- تنفيذ متزامن حقيقي
أنواع التوازي:
- توازي البيانات: نفس العملية على مجموعات بيانات مختلفة (مثل معالجة الصور)
- توازي المهام: مهام مختلفة على نوى مختلفة
٥ جدولة المعالج
📊 معايير الجدولة
| المعيار | الهدف | الصيغة/الوصف |
|---|---|---|
| استغلال المعالج | تعظيم | إبقاء المعالج مشغولاً (٤٠٪-٩٠٪) |
| الإنتاجية | تعظيم | عدد العمليات المُنجزة لكل وحدة زمنية |
| زمن الإنجاز | تقليل | وقت الإكمال - وقت الوصول |
| زمن الانتظار | تقليل | زمن الإنجاز - وقت الانفجار |
| زمن الاستجابة | تقليل | أول استجابة - وقت الوصول |
زمن الإنجاز = زمن الانتظار + وقت الانفجار
زمن الانتظار = زمن الإنجاز - وقت الانفجار
زمن الانتظار = زمن الإنجاز - وقت الانفجار
🎯 خوارزميات الجدولة
١. من يأتي أولاً يُخدم أولاً (FCFS)
- النوع: غير استباقية
- الترتيب: حسب وقت وصول العملية
- ❌ تأثير القافلة (العمليات القصيرة تنتظر الطويلة)
- ✅ سهلة التنفيذ
٢. الأقصر وظيفةً أولاً (SJF)
- النوع: يمكن أن تكون استباقية أو غير استباقية
- الترتيب: أقصر وقت انفجار أولاً
- ✅ مثالية (أقل متوسط زمن انتظار)
- ❌ لا يمكن معرفة أوقات الانفجار المستقبلية (يجب تقديرها)
- ❌ تجويع محتمل للعمليات الطويلة
متوسط التنبؤ بانفجار المعالج التالي:
τ(n+1) = α × t(n) + (1-α) × τ(n)
حيث α عادة = ٠.٥
τ(n+1) = α × t(n) + (1-α) × τ(n)
حيث α عادة = ٠.٥
٣. جدولة الأولويات
- النوع: يمكن أن تكون استباقية أو غير استباقية
- الترتيب: أعلى أولوية أولاً (رقم أصغر = أولوية أعلى)
- ❌ مشكلة التجويع
- ✅ الحل: التقادم (زيادة الأولوية مع مرور الوقت)
٤. Round Robin (RR)
- النوع: استباقية
- الترتيب: كل عملية تحصل على كم زمني (١٠-١٠٠ ملي ثانية)
- ✅ جيدة لأنظمة المشاركة الزمنية
- ✅ توزيع عادل
- ⚠️ إذا كان الكم كبيرًا جدًا → يصبح FCFS
- ⚠️ إذا كان الكم صغيرًا جدًا → تبديل سياق كثير
قاعدة: ٨٠٪ من انفجارات المعالج يجب أن تكون أقصر من الكم الزمني
سابق اختبار: عمليات بأوقات انفجار وأولويات مختلفة
المعطيات: P1(BT=٤, Pri=٣), P2(BT=٣, Pri=١), P3(BT=٨, Pri=٤), P4(BT=٧, Pri=٢), P5(BT=٥, Pri=٣)
كلها وصلت وقت ٠.
جدولة الأولويات (رقم أصغر = أولوية أعلى):
جانت: P2(٠-٣) | P4(٣-١٠) | P1(١٠-١٤) | P5(١٤-١٩) | P3(١٩-٢٧)
أوقات الانتظار: P1=١٠, P2=٠, P3=١٩-٨=١١, P4=٣, P5=١٤-٥=٩
المعطيات: P1(BT=٤, Pri=٣), P2(BT=٣, Pri=١), P3(BT=٨, Pri=٤), P4(BT=٧, Pri=٢), P5(BT=٥, Pri=٣)
كلها وصلت وقت ٠.
جدولة الأولويات (رقم أصغر = أولوية أعلى):
جانت: P2(٠-٣) | P4(٣-١٠) | P1(١٠-١٤) | P5(١٤-١٩) | P3(١٩-٢٧)
أوقات الانتظار: P1=١٠, P2=٠, P3=١٩-٨=١١, P4=٣, P5=١٤-٥=٩
🔄 استباقي مقابل غير استباقي
غير استباقي
- العملية تبقى في المعالج حتى تنتهي أو تنتظر
- أمثلة: FCFS، SJF (غير استباقي)
- لا حالات سباق على البيانات المشتركة
استباقي
- يمكن مقاطعة العملية
- أمثلة: RR، SJF (استباقي/SRTF)، الأولويات (استباقي)
- قد يسبب حالات سباق
📐 مسألة تطبيقية
تطبيق: احسب زمن الانتظار وزمن الإنجاز
العمليات: P1(BT=٢٤), P2(BT=٣), P3(BT=٣)
الترتيب: P1, P2, P3، كلها وصلت t=٠
FCFS:
جانت: P1(٠-٢٤) | P2(٢٤-٢٧) | P3(٢٧-٣٠)
WT: P1=٠, P2=٢٤, P3=٢٧
متوسط WT = (٠+٢٤+٢٧)/٣ = ١٧ms
SJF:
جانت: P2(٠-٣) | P3(٣-٦) | P1(٦-٣٠)
WT: P1=٦, P2=٠, P3=٣
متوسط WT = (٦+٠+٣)/٣ = ٣ms ✅ أمثل!
العمليات: P1(BT=٢٤), P2(BT=٣), P3(BT=٣)
الترتيب: P1, P2, P3، كلها وصلت t=٠
FCFS:
جانت: P1(٠-٢٤) | P2(٢٤-٢٧) | P3(٢٧-٣٠)
WT: P1=٠, P2=٢٤, P3=٢٧
متوسط WT = (٠+٢٤+٢٧)/٣ = ١٧ms
SJF:
جانت: P2(٠-٣) | P3(٣-٦) | P1(٦-٣٠)
WT: P1=٦, P2=٠, P3=٣
متوسط WT = (٦+٠+٣)/٣ = ٣ms ✅ أمثل!
٦ مزامنة العمليات
⚠️ مشكلة القسم الحرج
حالة السباق: عدة عمليات تصل إلى بيانات مشتركة في نفس الوقت، النتيجة تعتمد على ترتيب التنفيذ
قسم حرج: قطعة كود تصل إلى موارد مشتركة
الحل يجب أن يحقق ٣ متطلبات:
- الاستبعاد المتبادل: عملية واحدة فقط في القسم الحرج في كل مرة
- التقدم: فقط العمليات اللي مو في قسمها المتبقي تقرر من يدخل القسم الحرج بعدين
- الانتظار المحدود: حد لعدد مرات دخول الآخرين للقسم الحرج قبل عملية تنتظر
🔒 السيمافورات
السيمافور S: متغير صحيح يُوصل إليه فقط بواسطة:
- wait(S): S--; إذا S<٠، احجب
- signal(S): S++; أيقظ عملية محجوبة إذا وجدت
// wait تقليدي (انتظار نشط)
wait(S) {
while (S <= 0); // انتظار نشط
S--;
}
// signal تقليدي
signal(S) {
S++;
}
// تطبيق حديث (بدون انتظار نشط)
wait(S) {
S--;
if (S < 0) {
أضف هذه العملية إلى S->list;
block();
}
}
signal(S) {
S++;
if (S <= 0) {
أزل عملية P من S->list;
wakeup(P);
}
}
الأنواع:
- سيمافور ثنائي (Mutex): القيمة ٠ أو ١
- سيمافور عددي: القيمة يمكن أن تكون أي عدد صحيح
سيمافور مُهيأ إلى ١ = قفل Mutex!
🍝 المشاكل الكلاسيكية
١. المخزن المؤقت المحدود (منتج-مستهلك)
// بيانات مشتركة
semaphore mutex = 1; // استبعاد متبادل
semaphore empty = n; // عدد الخانات الفارغة
semaphore full = 0; // عدد الخانات الممتلئة
// المنتج
do {
// أنتج عنصرًا
wait(empty); // انتظر خانة فارغة
wait(mutex); // ادخل القسم الحرج
// أضف عنصرًا للمخزن
signal(mutex); // اخرج من القسم الحرج
signal(full); // زد عدد الممتلئة
} while(true);
// المستهلك
do {
wait(full); // انتظر خانة ممتلئة
wait(mutex); // ادخل القسم الحرج
// أزل عنصرًا من المخزن
signal(mutex); // اخرج من القسم الحرج
signal(empty); // زد عدد الفارغة
// استهلك العنصر
} while(true);
٢. مشكلة القراء والكتاب
// بيانات مشتركة
semaphore rw_mutex = 1; // استبعاد متبادل للكتاب
semaphore mutex = 1; // يحمي readcount
int readcount = 0;
// الكاتب
do {
wait(rw_mutex);
// يتم تنفيذ الكتابة
signal(rw_mutex);
} while(true);
// القارئ
do {
wait(mutex);
readcount++;
if (readcount == 1) // أول قارئ
wait(rw_mutex); // امنع الكتاب
signal(mutex);
// يتم تنفيذ القراءة
wait(mutex);
readcount--;
if (readcount == 0) // آخر قارئ
signal(rw_mutex); // اسمح للكتاب
signal(mutex);
} while(true);
٣. مشكلة الفلاسفة
- ٥ فلاسفة، ٥ أعواد
- يحتاج عودين ليأكل
- ❌ جمود إذا كل فيلسوف أخذ العود الأيسر
- السماح بأقصى ٤ فلاسفة على الطاولة
- أخذ العودين دفعة واحدة
- الفلاسفة الفرديون يأخذون اليسار أولاً، الزوجيون يأخذون اليمين أولاً
💀 الجمود
الشروط الضرورية (كلها لازم تتحقق):
- الاستبعاد المتبادل: مورد واحد على الأقل غير قابل للمشاركة
- الاحتجاز والانتظار: عملية تحتجز موارد وتنتظر المزيد
- عدم الاستباق: الموارد لا يمكن أخذها قسرًا
- الانتظار الدائري: P1 تنتظر P2، P2 تنتظر P3، ...، Pn تنتظر P1
اختصار: "احتجاز، انتظار، استباق، دائري" ← الشروط الأربعة
٨ إدارة الذاكرة الرئيسية
📍 ربط العناوين
عنوان منطقي مقابل فيزيائي:
- منطقي (افتراضي): يولده المعالج، يراه البرنامج
- فيزيائي: الموقع الفعلي في الرام، تراه وحدة الذاكرة
| وقت الربط | متى | قابل لإعادة التموضع؟ |
|---|---|---|
| وقت الترجمة | إذا كان موقع الذاكرة معروفًا مسبقًا | لا (كود مطلق) |
| وقت التحميل | عند تحميل البرنامج في الذاكرة | نعم (كود قابل لإعادة التموضع) |
| وقت التنفيذ | أثناء تنفيذ البرنامج | نعم (يحتاج MMU) |
🗺️ وحدة إدارة الذاكرة (MMU)
MMU: جهاز عتادي يرسم العناوين المنطقية إلى فيزيائية
عنوان فيزيائي = مسجل الأساس + عنوان منطقي
مسجلات الأساس والحد:
- الأساس: عنوان البداية الفيزيائي
- الحد: حجم مساحة العنوان المنطقي
- الحماية: إذا (عنوان منطقي >= حد) → خطأ!
🧩 تخصيص الذاكرة المتجاورة
تقسيم ثابت:
- الذاكرة مقسمة إلى أقسام ثابتة الحجم
- ❌ تجزؤ داخلي
- ❌ يحد من تعدد البرمجة
تقسيم متغير:
- تخصيص ديناميكي بناءً على حجم العملية
- ❌ تجزؤ خارجي
- الحل: الضغط (يحتاج إعادة تموضع ديناميكي)
خوارزميات التخصيص:
- الأول المناسب: خصص أول فجوة مناسبة (الأسرع)
- الأفضل مناسبة: خصص أصغر فجوة مناسبة (أصغر بقايا)
- الأسوأ مناسبة: خصص أكبر فجوة (أكبر بقايا)
سابق اختبار: أقسام الذاكرة: ٣٠٠كيلوبايت، ٦٠٠كيلوبايت، ٣٥٠كيلوبايت، ٢٠٠كيلوبايت، ٧٥٠كيلوبايت، ١٢٥كيلوبايت
العمليات: ١١٥كيلوبايت، ٥٠٠كيلوبايت، ٣٥٨كيلوبايت، ٢٠٠كيلوبايت، ٣٧٥كيلوبايت
الأفضل مناسبة:
١١٥كيلوبايت → ١٢٥كيلوبايت (١٠كيلوبايت باقي)
٥٠٠كيلوبايت → ٦٠٠كيلوبايت (١٠٠كيلوبايت باقي)
٣٥٨كيلوبايت → ٧٥٠كيلوبايت (٣٩٢كيلوبايت باقي)
٢٠٠كيلوبايت → ٢٠٠كيلوبايت (٠ باقي)
٣٧٥كيلوبايت → ٣٩٢كيلوبايت ✅ الكل يركب!
العمليات: ١١٥كيلوبايت، ٥٠٠كيلوبايت، ٣٥٨كيلوبايت، ٢٠٠كيلوبايت، ٣٧٥كيلوبايت
الأفضل مناسبة:
١١٥كيلوبايت → ١٢٥كيلوبايت (١٠كيلوبايت باقي)
٥٠٠كيلوبايت → ٦٠٠كيلوبايت (١٠٠كيلوبايت باقي)
٣٥٨كيلوبايت → ٧٥٠كيلوبايت (٣٩٢كيلوبايت باقي)
٢٠٠كيلوبايت → ٢٠٠كيلوبايت (٠ باقي)
٣٧٥كيلوبايت → ٣٩٢كيلوبايت ✅ الكل يركب!
📄 التصفح
المفهوم:
- تقسيم الذاكرة المنطقية إلى صفحات (حجم ثابت)
- تقسيم الذاكرة الفيزيائية إلى إطارات (نفس الحجم)
- حجم الصفحة = حجم الإطار (قوة ٢، مثال ٤كيلوبايت)
- ✅ لا تجزؤ خارجي
- ❌ تجزؤ داخلي (آخر صفحة)
هيكل العنوان المنطقي:
عنوان منطقي = [رقم الصفحة | إزاحة الصفحة]
إذا كانت مساحة العنوان المنطقي = ٢^م، حجم الصفحة = ٢^ن
رقم الصفحة = م - ن بت
إزاحة الصفحة = ن بت
إذا كانت مساحة العنوان المنطقي = ٢^م، حجم الصفحة = ٢^ن
رقم الصفحة = م - ن بت
إزاحة الصفحة = ن بت
ترجمة العنوان:
- استخرج رقم الصفحة (p) من العنوان المنطقي
- ابحث عن رقم الإطار (f) في جدول الصفحات[p]
- عنوان فيزيائي = (f × حجم_الإطار) + إزاحة
سابق اختبار: عملية لها ٤ صفحات، حجم الصفحة = ١كيلوبايت
جدول الصفحات: [٠→٥, ١→١٠, ٢→١٣, ٣→٧]
عنوان منطقي = ١٥٠٠
الحل:
حجم الصفحة = ١٠٢٤ بايت
رقم الصفحة = ١٥٠٠ / ١٠٢٤ = ١
الإزاحة = ١٥٠٠ % ١٠٢٤ = ٤٧٦
رقم الإطار = page_table[١] = ١٠
عنوان فيزيائي = ١٠ × ١٠٢٤ + ٤٧٦ = ١٠٧١٦
جدول الصفحات: [٠→٥, ١→١٠, ٢→١٣, ٣→٧]
عنوان منطقي = ١٥٠٠
الحل:
حجم الصفحة = ١٠٢٤ بايت
رقم الصفحة = ١٥٠٠ / ١٠٢٤ = ١
الإزاحة = ١٥٠٠ % ١٠٢٤ = ٤٧٦
رقم الإطار = page_table[١] = ١٠
عنوان فيزيائي = ١٠ × ١٠٢٤ + ٤٧٦ = ١٠٧١٦
سابق اختبار: مساحة العنوان المنطقي = ٢٥٦ صفحة، حجم الصفحة = ٤كيلوبايت
الذاكرة الفيزيائية = ٦٤ إطارًا
أ) كم بت في العنوان المنطقي؟
٢٥٦ × ٤كيلوبايت = ٢٥٦ × ٤٠٩٦ = ٢^٨ × ٢^١٢ = ٢^٢٠
الجواب: ٢٠ بت
ب) كم بت في العنوان الفيزيائي؟
٦٤ × ٤كيلوبايت = ٦٤ × ٤٠٩٦ = ٢^٦ × ٢^١٢ = ٢^١٨
الجواب: ١٨ بت
الذاكرة الفيزيائية = ٦٤ إطارًا
أ) كم بت في العنوان المنطقي؟
٢٥٦ × ٤كيلوبايت = ٢٥٦ × ٤٠٩٦ = ٢^٨ × ٢^١٢ = ٢^٢٠
الجواب: ٢٠ بت
ب) كم بت في العنوان الفيزيائي؟
٦٤ × ٤كيلوبايت = ٦٤ × ٤٠٩٦ = ٢^٦ × ٢^١٢ = ٢^١٨
الجواب: ١٨ بت
⚡ مخزن الترجمة المؤقت (TLB)
TLB: ذاكرة مخبئية عتادية سريعة لإدخالات جدول الصفحات
- صغير (٦٤-١٠٢٤ إدخال)
- بحث متوازي
- يحتوي ترجمات صفحات حديثة
وقت الوصول الفعال (EAT):
EAT = نسبة_الإصابة × (وقت_TLB + وقت_الذاكرة)
+ (١ - نسبة_الإصابة) × (وقت_TLB + وقت_جدول_الصفحات + وقت_الذاكرة)
EAT = نسبة_الإصابة × (وقت_TLB + وقت_الذاكرة)
+ (١ - نسبة_الإصابة) × (وقت_TLB + وقت_جدول_الصفحات + وقت_الذاكرة)
سابق اختبار:
وقت الذاكرة = ٥٠ns
وقت TLB = ٢ns
نسبة الإصابة = ٧٥٪
EAT = ٠.٧٥ × (٢ + ٥٠) + ٠.٢٥ × (٢ + ٥٠ + ٥٠)
EAT = ٠.٧٥ × ٥٢ + ٠.٢٥ × ١٠٢
EAT = ٣٩ + ٢٥.٥ = ٦٤.٥ns
وقت الذاكرة = ٥٠ns
وقت TLB = ٢ns
نسبة الإصابة = ٧٥٪
EAT = ٠.٧٥ × (٢ + ٥٠) + ٠.٢٥ × (٢ + ٥٠ + ٥٠)
EAT = ٠.٧٥ × ٥٢ + ٠.٢٥ × ١٠٢
EAT = ٣٩ + ٢٥.٥ = ٦٤.٥ns
🗂️ التقسيم
المفهوم:
- تقسيم الذاكرة حسب وحدات منطقية (دالة، مصفوفة، مكدس)
- أقسام ذات حجم متغير
- رؤية المبرمج للذاكرة
عنوان منطقي:
<رقم القسم، إزاحة>
جدول الأقسام:
- الأساس: عنوان البداية الفيزيائي
- الحد: طول القسم
- الحماية: إذا (الإزاحة >= حد) → خطأ!
إذا الإزاحة < حد:
عنوان فيزيائي = أساس + إزاحة
وإلا:
خطأ تجزئة!
عنوان فيزيائي = أساس + إزاحة
وإلا:
خطأ تجزئة!
مثال: جدول الأقسام
[قسم ٠: أساس=١٢٠٠، حد=١٠٠٠]
[قسم ١: أساس=٤٠٠٠، حد=٦٠٠]
[قسم ٢: أساس=٢٠٠٠، حد=١٤٠٠]
عنوان منطقي <١, ٥٠٠>:
٥٠٠ < ٦٠٠ ✅ صالح
فيزيائي = ٤٠٠٠ + ٥٠٠ = ٤٥٠٠
عنوان منطقي <١, ٦٠٠>:
٦٠٠ >= ٦٠٠ ❌ غير قانوني!
[قسم ٠: أساس=١٢٠٠، حد=١٠٠٠]
[قسم ١: أساس=٤٠٠٠، حد=٦٠٠]
[قسم ٢: أساس=٢٠٠٠، حد=١٤٠٠]
عنوان منطقي <١, ٥٠٠>:
٥٠٠ < ٦٠٠ ✅ صالح
فيزيائي = ٤٠٠٠ + ٥٠٠ = ٤٥٠٠
عنوان منطقي <١, ٦٠٠>:
٦٠٠ >= ٦٠٠ ❌ غير قانوني!
⚖️ التصفح مقابل التقسيم
التصفح
- صفحات ثابتة الحجم
- نظرة فيزيائية
- لا تجزؤ خارجي
- تجزؤ داخلي
- غير مرئي للمبرمج
التقسيم
- أقسام متغيرة الحجم
- نظرة منطقية
- تجزؤ خارجي
- لا تجزؤ داخلي
- مرئي للمبرمج
٩ الذاكرة الافتراضية
💭 مفهوم الذاكرة الافتراضية
الفوائد:
- مساحة عنوان منطقي > الذاكرة الفيزيائية
- برامج أكثر في الذاكرة في نفس الوقت
- إدخال/إخراج أقل للتحميل
- بدء تشغيل أسرع للبرامج
التصفح عند الطلب:
- تحميل الصفحات فقط عند الحاجة
- مبادل كسول (لا يبادل إلا عند الضرورة)
- يستخدم بت صالح/غير صالح في جدول الصفحات
💥 خطأ الصفحة
خطأ الصفحة يحدث عندما:
- عملية تشير إلى صفحة ليست في الذاكرة
- إدخال جدول الصفحات به بت غير صالح
خطوات معالجة خطأ الصفحة:
- تحقق من الجدول الداخلي (PCB) - مرجع صالح أم لا؟
- إذا غير صالح → أنهِ العملية
- إذا صالح لكن ليس في الذاكرة → أحضره:
- احصل على إطار فارغ
- مبادلة الصفحة من القرص إلى الإطار
- حدث جدول الصفحات (اضبط بت صالح)
- أعد تشغيل التعليمات
وقت الوصول الفعال (EAT):
EAT = (١ - p) × وقت_الذاكرة + p × وقت_خدمة_خطأ_الصفحة
حيث p = معدل خطأ الصفحة (٠ ≤ p ≤ ١)
EAT = (١ - p) × وقت_الذاكرة + p × وقت_خدمة_خطأ_الصفحة
حيث p = معدل خطأ الصفحة (٠ ≤ p ≤ ١)
سابق اختبار:
وقت الذاكرة = ٢٠٠ns
وقت خدمة خطأ الصفحة = ٨ms = ٨,٠٠٠,٠٠٠ns
معدل خطأ الصفحة = ١/١٠٠٠ = ٠.٠٠١
EAT = (١ - ٠.٠٠١) × ٢٠٠ + ٠.٠٠١ × ٨,٠٠٠,٠٠٠
EAT = ٠.٩٩٩ × ٢٠٠ + ٨,٠٠٠
EAT = ١٩٩.٨ + ٨,٠٠٠ = ٨,١٩٩.٨ns ≈ ٨.٢μs
وقت الذاكرة = ٢٠٠ns
وقت خدمة خطأ الصفحة = ٨ms = ٨,٠٠٠,٠٠٠ns
معدل خطأ الصفحة = ١/١٠٠٠ = ٠.٠٠١
EAT = (١ - ٠.٠٠١) × ٢٠٠ + ٠.٠٠١ × ٨,٠٠٠,٠٠٠
EAT = ٠.٩٩٩ × ٢٠٠ + ٨,٠٠٠
EAT = ١٩٩.٨ + ٨,٠٠٠ = ٨,١٩٩.٨ns ≈ ٨.٢μs
🔄 خوارزميات استبدال الصفحات
متى نستخدمها: عندما لا توجد إطارات فارغة متاحة
١. FIFO (أولاً يدخل أولاً يخرج)
- استبدال أقدم صفحة في الذاكرة
- سهلة التنفيذ
- ❌ تعاني من شذوذ بيلادي (إطارات أكثر قد تسبب أخطاء أكثر)
٢. الأمثل (OPT)
- استبدال الصفحة التي لن تُستخدم لأطول وقت
- ✅ أقل أخطاء صفحة
- ❌ مستحيل التنفيذ (يحتاج معرفة مستقبلية)
- يستخدم كمعيار
٣. LRU (الأقل استخدامًا مؤخرًا)
- استبدال الصفحة التي لم تُستخدم لأطول وقت
- ✅ تقريب جيد للأمثل
- ✅ لا يعاني من شذوذ بيلادي
- التنفيذ: مكدس أو عدادات
سابق اختبار: سلسلة المراجع: ٧,٢,٣,١,٢,٥,٣,٤,٦,٧,٧,١,٠,٥,٤,٦,٢,٣,٠,١
٣ إطارات متاحة
حل LRU:
إجمالي أخطاء الصفحة: ١٨
٣ إطارات متاحة
حل LRU:
| ٧ | ٢ | ٣ | ١ | ٢ | ٥ | ٣ | ٤ | ٦ | ٧ | ٧ | ١ | ٠ | ٥ | ٤ | ٦ | ٢ | ٣ | ٠ | ١ |
| ٧ | ٧ | ٧ | ١ | ١ | ١ | ٣ | ٣ | ٣ | ٧ | ٧ | ٧ | ٧ | ٥ | ٥ | ٥ | ٢ | ٢ | ٢ | ١ |
| ٢ | ٢ | ٢ | ٢ | ٢ | ٢ | ٤ | ٤ | ٤ | ٤ | ١ | ١ | ١ | ٤ | ٤ | ٤ | ٣ | ٣ | ٣ | |
| ٣ | ٣ | ٣ | ٥ | ٥ | ٥ | ٦ | ٦ | ٦ | ٦ | ٠ | ٠ | ٠ | ٦ | ٦ | ٦ | ٠ | ٠ |
مقارنة سريعة: FIFO بسيط لكن عنده بيلادي؛ OPT أمثل لكن مستحيل؛ LRU عملي وجيد
🌀 التخبط
التخبط: العملية تقضي وقتًا في التصفح أكثر من التنفيذ
الأسباب:
- العملية ليس لديها إطارات كافية
- درجة عالية من تعدد البرمجة
- ذاكرة فيزيائية غير كافية
الحلول:
- تقليل درجة تعدد البرمجة
- زيادة الذاكرة الفيزيائية (RAM)
- استخدام خوارزمية استبدال محلية
- توفير إطارات كافية لكل عملية
سابق اختبار: قياسات النظام:
استخدام المعالج: ١٠٪
قرص التصفح: ٩٧.٧٪
التشخيص: النظام يتخبط!
الحلول: (١) تقليل تعدد البرمجة (٢) زيادة الرام
استخدام المعالج: ١٠٪
قرص التصفح: ٩٧.٧٪
التشخيص: النظام يتخبط!
الحلول: (١) تقليل تعدد البرمجة (٢) زيادة الرام
١١ أنظمة الملفات
📁 مفهوم الملف
الملف: مجموعة مسماة من المعلومات ذات الصلة مخزنة على تخزين ثانوي
سمات الملف:
- الاسم: شكل قابل للقراءة البشرية
- المعرف: علامة فريدة (رقم inode)
- النوع: نص، ثنائي، قابل للتنفيذ
- الموقع: مؤشر للجهاز والموقع
- الحجم: حجم الملف الحالي
- الحماية: أذونات القراءة، الكتابة، التنفيذ
- الوقت والتاريخ: الإنشاء، آخر وصول، آخر تعديل
عمليات الملف:
- إنشاء: إيجاد مساحة، إضافة إدخال دليل
- فتح: تحميل FCB إلى الذاكرة (جدول الملفات المفتوحة)
- قراءة/كتابة: استخدام مؤشر الملف
- Seek: إعادة تموضع مؤشر الملف
- إغلاق: إزالة من جدول الملفات المفتوحة
- حذف: إزالة إدخال الدليل، تحرير المساحة
- اقتطاع: حذف المحتويات، الاحتفاظ بالسمات
📂 هيكل الدليل
١. دليل أحادي المستوى
- كل الملفات في دليل واحد
- ✅ بسيط
- ❌ مشكلة التسمية (كل الأسماء يجب أن تكون فريدة)
- ❌ لا تجميع
٢. دليل ثنائي المستوى
- دليل رئيسي للملفات + أدلة مستخدمين فرعية
- ✅ يعزل المستخدمين
- ✅ بحث فعال
- ❌ لا قدرة على التجميع
٣. دليل شجري
- هيكل هرمي (الأكثر شيوعًا)
- ✅ بحث فعال
- ✅ قدرة على التجميع
- ✅ مفهوم الدليل الحالي
- المسار المطلق: /home/user/file.txt
- المسار النسبي: ../file.txt
٤. دليل غير دائري
- يسمح بمشاركة الملفات/الأدلة الفرعية
- يستخدم روابط (صلبة أو رمزية)
- ⚠️ مشكلة الحذف (مؤشرات معلقة)
🔐 حماية الملفات
قائمة التحكم بالوصول: تحدد المستخدمين والعمليات المسموح بها
حماية UNIX (rwx):
| الفئة | الوصف |
|---|---|
| المالك | منشئ الملف |
| المجموعة | مجموعة من المستخدمين يشاركون الوصول |
| الآخرون | كل المستخدمين الآخرين |
الأذونات:
- r (قراءة): قراءة محتويات الملف
- w (كتابة): كتابة/تعديل الملف
- x (تنفيذ): تنفيذ الملف
🎯 طرق الوصول
وصول تسلسلي
- السجلات تُعالج بالترتيب
- مثل شريط
- تستخدم بواسطة المحررات، المترجمات
وصول مباشر (عشوائي)
- الوصول لأي سجل مباشرة
- سجلات ثابتة الطول
- تستخدم بواسطة قواعد البيانات
وصول مفهرس:
- ملف فهرس يشير إلى البيانات الفعلية
- يمكن أن يكون له فهارس متعددة المستويات
- مثال: ISAM
⚡ مرجع سريع وصيغ
📐 صيغ أساسية
التصفح:
رقم الصفحة = عنوان منطقي / حجم الصفحة
إزاحة الصفحة = عنوان منطقي % حجم الصفحة
عنوان فيزيائي = (رقم الإطار × حجم الإطار) + إزاحة
بتات العنوان المنطقي = log₂(صفحات × حجم الصفحة)
بتات العنوان الفيزيائي = log₂(إطارات × حجم الإطار)
رقم الصفحة = عنوان منطقي / حجم الصفحة
إزاحة الصفحة = عنوان منطقي % حجم الصفحة
عنوان فيزيائي = (رقم الإطار × حجم الإطار) + إزاحة
بتات العنوان المنطقي = log₂(صفحات × حجم الصفحة)
بتات العنوان الفيزيائي = log₂(إطارات × حجم الإطار)
TLB وقت الوصول الفعال:
EAT = h × (وقت_TLB + وقت_الذاكرة) + (١-h) × (وقت_TLB + وقت_جدول_الصفحات + وقت_الذاكرة)
حيث h = نسبة الإصابة
EAT = h × (وقت_TLB + وقت_الذاكرة) + (١-h) × (وقت_TLB + وقت_جدول_الصفحات + وقت_الذاكرة)
حيث h = نسبة الإصابة
EAT مع خطأ الصفحة:
EAT = (١-p) × وقت_الذاكرة + p × وقت_خدمة_خطأ_الصفحة
حيث p = معدل خطأ الصفحة
EAT = (١-p) × وقت_الذاكرة + p × وقت_خدمة_خطأ_الصفحة
حيث p = معدل خطأ الصفحة
الجدولة:
زمن الإنجاز = وقت الإكمال - وقت الوصول
زمن الانتظار = زمن الإنجاز - وقت الانفجار
زمن الاستجابة = أول استجابة - وقت الوصول
زمن الإنجاز = وقت الإكمال - وقت الوصول
زمن الانتظار = زمن الإنجاز - وقت الانفجار
زمن الاستجابة = أول استجابة - وقت الوصول
الوصول للقرص:
وقت الوصول = وقت البحث + وقت الدوران + وقت النقل
وقت الوصول = وقت البحث + وقت الدوران + وقت النقل
🎯 نصائح سريعة للاختبارات
عملية مقابل خيط: عملية = ثقيلة، ذاكرة منفصلة؛ خيط = خفيف، ذاكرة مشتركة
قيم إرجاع fork(): ٠ للابنة، PID الابنة للأم، -١ عند الخطأ
بت الوضع: ٠ = وضع نواة، ١ = وضع مستخدم
تجزؤ خارجي: تقسيم متغير، تقسيم
تجزؤ داخلي: تقسيم ثابت، تصفح
تجزؤ داخلي: تقسيم ثابت، تصفح
حجم الصفحة = حجم الإطار (دايمًا متساويان!)
شذوذ بيلادي: فقط FIFO يعاني منه (ليس LRU أو الأمثل)
شروط الجمود (كلها مطلوبة): استبعاد متبادل، احتجاز وانتظار، عدم استباق، انتظار دائري
خوارزميات استباقية: RR، SRTF، أولويات استباقية
خوارزميات غير استباقية: FCFS، SJF، أولويات غير استباقية
خوارزميات غير استباقية: FCFS، SJF، أولويات غير استباقية
🔢 تحويلات شائعة
| الوحدة | القيمة |
|---|---|
| ١ كيلوبايت | ١٠٢٤ بايت = ٢^١٠ |
| ١ ميجابايت | ١٠٢٤ كيلوبايت = ٢^٢٠ بايت |
| ١ جيجابايت | ١٠٢٤ ميجابايت = ٢^٣٠ بايت |
| ١ ملي ثانية | ١,٠٠٠ ميكروثانية = ١,٠٠٠,٠٠٠ نانوثانية |
| ١ ميكروثانية | ١,٠٠٠ نانوثانية |
✅ أخطاء شائعة تتجنبها في الاختبار
❌ خطأ: الاعتقاد أن حجم الصفحة ≠ حجم الإطار
✅ صحيح: حجم الصفحة دايمًا يساوي حجم الإطار
✅ صحيح: حجم الصفحة دايمًا يساوي حجم الإطار
❌ خطأ: fork() يرجع PID الابنة للابنة
✅ صحيح: fork() يرجع ٠ للابنة، PID الابنة للأم
✅ صحيح: fork() يرجع ٠ للابنة، PID الابنة للأم
❌ خطأ: الخيوط تشارك المكدس
✅ صحيح: كل خيط له مكدسه الخاص؛ يشاركون الكود، البيانات، الكومة
✅ صحيح: كل خيط له مكدسه الخاص؛ يشاركون الكود، البيانات، الكومة
❌ خطأ: زمن الانتظار يشمل وقت الانفجار
✅ صحيح: زمن الانتظار = زمن الإنجاز - وقت الانفجار
✅ صحيح: زمن الانتظار = زمن الإنجاز - وقت الانفجار
❌ خطأ: التصفح يسبب تجزؤًا خارجيًا
✅ صحيح: التصفح يزيل التجزؤ الخارجي، لكن يسبب تجزؤًا داخليًا
✅ صحيح: التصفح يزيل التجزؤ الخارجي، لكن يسبب تجزؤًا داخليًا
📝 قائمة المراجعة النهائية
قبل الاختبار، تأكد أنك تستطيع:
- ✅ حساب رقم الصفحة والإزاحة من عنوان منطقي
- ✅ تحويل عنوان منطقي إلى فيزيائي باستخدام جدول الصفحات
- ✅ حساب وقت الوصول الفعال مع TLB
- ✅ رسم مخططات جانت لكل خوارزميات الجدولة
- ✅ حساب زمن الانتظار وزمن الإنجاز
- ✅ تتبع تنفيذ fork() وحساب عدد العمليات المنشأة
- ✅ تنفيذ منتج-مستهلك بالسيمافورات
- ✅ تنفيذ استبدال الصفحات (FIFO، LRU، الأمثل)
- ✅ حساب البتات اللازمة للعناوين المنطقية/الفيزيائية
- ✅ فهم الفرق بين العملية والخيط
- ✅ معرفة متى تستخدم كل خوارزمية تخصيص (أول مناسب، أفضل مناسب، أسوأ مناسب)
- ✅ تحديد شروط الجمود
- ✅ فهم فوائد الذاكرة الافتراضية وأخطاء الصفحة