📚 أنظمة التشغيل CS330

ملخص شامل للاختبارات

جامعة الأمير سلطان

١ مقدمة في أنظمة التشغيل

🎯 وش هو نظام التشغيل؟

تعريف: برنامج يشتغل كوسيط بين المستخدمين وعتاد الكمبيوتر.
  • الأهداف: تنفيذ برامج المستخدم، تسهيل استخدام النظام، استغلال العتاد بكفاءة
  • النواة (Kernel): البرنامج الوحيد اللي دايمًا شغال على الكمبيوتر (جوهر نظام التشغيل)
تذكر المكونات الأربعة: العتاد → نظام التشغيل → التطبيقات → المستخدمين

💾 تنظيم نظام الكمبيوتر

المكون وقت الوصول تطاير
المسجلات ~١ نانوثانية متطايرة
الذاكرة المخبئية ~٢-١٠ نانوثانية متطايرة
الذاكرة الرئيسية (RAM) ~١٠٠ نانوثانية متطايرة
SSD ~١٠٠ ميكروثانية غير متطايرة
القرص الصلب ~٨-٥٠ ملي ثانية غير متطايرة
اختصار: "RegistersCacheRAM" → RCR → أسرع وأغلى

⚡ المقاطعات

الأنواع:
  • مقاطعة عتادية: من أجهزة الإدخال/الإخراج (كيبورد، فأرة، قرص)
  • مقاطعة برمجية (Trap/Exception): من أخطاء أو استدعاءات نظام
عملية معالجة المقاطعة:
  1. حفظ PCB (عداد البرنامج والمسجلات)
  2. تحديد نوع المقاطعة (polling أو vectored)
  3. تنفيذ روتين خدمة المقاطعة (ISR)
  4. استعادة المعلومات المحفوظة
  5. استئناف التنفيذ
متجه المقاطعة = جدول عناوين يشير إلى روتينات خدمة المقاطعة

🚀 DMA (الوصول المباشر للذاكرة)

  • يستخدم لأجهزة الإدخال/الإخراج عالية السرعة
  • ينقل البيانات مباشرة بين الإدخال/الإخراج والذاكرة بدون المعالج
  • مقاطعة واحدة فقط لكل كتلة (مو لكل بايت)
سؤال: وش هو الأفضل لنقل كميات كبيرة من البيانات بين أجهزة الإدخال/الإخراج والذاكرة الرئيسية بدون تدخل المعالج؟
الجواب: DMA

🖥️ أنظمة متعددة المعالجات

متماثلة (SMP)

  • كل معالج يؤدي كل المهام
  • مافي علاقة رئيسي-تابع
  • معالجات متساوية

غير متماثلة (AMP)

  • معالج رئيسي يتحكم في التابعين
  • علاقة مدير-موظف
  • تستخدم في الأنظمة الكبيرة
المزايا:
  1. زيادة الإنتاجية: شغل أكثر بوقت أقل
  2. اقتصاد الحجم: تكلفة أقل من عدة أنظمة أحادية المعالج
  3. زيادة الموثوقية: التدهور التدريجي/تحمل الأخطاء

🔐 التشغيل ثنائي الوضع

الوضع قيمة البت الغرض
وضع النواة/النظام ٠ تنفيذ نظام التشغيل، تعليمات مميزة
وضع المستخدم ١ تنفيذ تطبيقات المستخدم
استدعاء النظام يغيّر الوضع إلى نواة، والرجوع يعيده لوضع المستخدم
سؤال: التعليمات المميزة يمكن تنفيذها فقط في؟
الجواب: وضع النواة (mode bit = ٠)

٢ هياكل أنظمة التشغيل

🛠️ خدمات نظام التشغيل

للمستخدمين:
  • واجهة المستخدم: CLI، GUI، شاشة لمس
  • تنفيذ البرامج: تحميل، تشغيل، إنهاء البرامج
  • عمليات الإدخال/الإخراج: المستخدمون لا يستطيعون تنفيذ I/O مباشرة
  • التعامل مع نظام الملفات: قراءة، كتابة، إنشاء، حذف
  • الاتصالات: ذاكرة مشتركة أو تمرير رسائل
  • اكتشاف الأخطاء: كشف أخطاء المعالج، الذاكرة، الإدخال/الإخراج
لكفاءة النظام:
  • تخصيص الموارد: إدارة المعالج، الذاكرة، الملفات
  • المحاسبة: تتبع إحصائيات الاستخدام
  • الحماية والأمان: التحكم في الوصول، الدفاع ضد الهجمات

📞 استدعاءات النظام

تعريف: واجهة بين البرنامج الجاري ونظام التشغيل
  • يُوصل إليها عبر API (Win32, POSIX, Java)
  • كل استدعاء نظام له رقم
  • واجهة استدعاء النظام تحتفظ بجدول مفهرس
طرق تمرير المعاملات:
  1. المسجلات: أبسط، محدود بعدد المسجلات
  2. كتلة/جدول في الذاكرة: تمرير عنوان الكتلة
  3. المكدس: دفع المعاملات، سحبها بواسطة نظام التشغيل
الفئة أمثلة
التحكم في العمليات 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]_←_↓
قيد التشغيل → [مقاطعة] → جاهزة
قيد التشغيل → [خروج] → منتهية
الحالة الوصف
جديدة العملية قيد الإنشاء، يتم تهيئة PCB
جاهزة تنتظر أن تُسند إلى معالج
قيد التشغيل يتم تنفيذ التعليمات
منتظرة تنتظر إدخال/إخراج أو حدث
منتهية العملية أنهت تنفيذها
سؤال: عملية في حالة قيد التشغيل يمكن أن تنتقل إلى أي حالات؟
الجواب: جاهزة، منتظرة، منتهية

📦 كتلة التحكم في العملية (PCB)

PCB يحتوي على:
  • معرف العملية (PID)
  • حالة العملية (جاهزة، قيد التشغيل، إلخ)
  • عداد البرنامج (PC)
  • مسجلات المعالج
  • معلومات جدولة المعالج (أولوية، قوائم)
  • معلومات إدارة الذاكرة
  • معلومات المحاسبة (وقت المعالج، حدود الوقت)
  • معلومات حالة الإدخال/الإخراج (ملفات مفتوحة، أجهزة)
PCB يُخزّن في ذاكرة النواة، مو في قسم النص للعملية

🔀 تبديل السياق

الخطوات:
  1. حفظ PCB للعملية الحالية (المسجلات، PC، الحالة)
  2. تحميل PCB للعملية الجديدة
  3. استئناف تنفيذ العملية الجديدة
وقت تبديل السياق:
  • عبء خالص (مافي شغل مفيد أثناء التبديل)
  • يعتمد على دعم العتاد (بعض المعالجات لديها مجموعات مسجلات متعددة)
  • عادةً ١-١٠٠٠ ميكروثانية

📅 جدولة العمليات

المجدول اسم آخر الغرض التكرار
طويلة المدى جدول الوظائف اختيار أي وظائف تُحمل إلى قائمة الانتظار الجاهزة غير متكرر (ثواني/دقائق)
قصيرة المدى جدول المعالج اختيار أي عملية جاهزة تحصل على المعالج متكرر جدًا (أجزاء من الثانية)
متوسطة المدى المبادل مبادلة العمليات داخل/خارج الذاكرة متوسط
أنواع العمليات:
  • مقيدة بالإدخال/الإخراج: وقت أكثر في 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 = ٣٦٠٠
سؤال: كم عملية تنشأ بأربع استدعاءات fork() في حلقة؟
الجواب: ٢^٤ = ١٦ عملية (بما في ذلك الأم)
الابنة تحصل على نسخة من ذاكرة الأم (البيانات، الكومة، المكدس)، مو مشتركة!

💬 الاتصال بين العمليات (IPC)

ذاكرة مشتركة

  • أسرع - لا استدعاءات نظام بعد الإعداد
  • وصول مباشر للذاكرة
  • يحتاج مزامنة
  • جيد للبيانات الكبيرة

تمرير رسائل

  • أسهل - نظام التشغيل يتولى المزامنة
  • استدعاءات نظام send() و receive()
  • أبطأ بسبب استدعاءات النظام
  • جيد للرسائل الصغيرة

٤ الخيوط والتزامن

🧵 أساسيات الخيوط

الخيط = عملية خفيفة الوزن

الخيط هو وحدة أساسية لاستغلال المعالج ويتكون من:

  • معرف الخيط
  • عداد البرنامج
  • مجموعة المسجلات
  • المكدس
الخيوط تشارك داخل العملية:
  • قسم الكود
  • قسم البيانات (المتغيرات العامة)
  • الكومة
  • الملفات المفتوحة
  • موارد نظام التشغيل
كل خيط له خاصته:
  • المكدس
  • عداد البرنامج
  • المسجلات
سؤال: أي مما يلي لا تشاركه الخيوط؟
الجواب: عداد البرنامج والمكدس

✅ فوائد تعدد الخيوط

  1. الاستجابة: البرنامج يستمر حتى لو جزء منه محجوب (مثل متصفح ويب يحمل صورة والمستخدم يتفاعل)
  2. مشاركة الموارد: الخيوط تشارك الذاكرة والموارد (أسهل من IPC)
  3. الاقتصاد:
    • إنشاء خيط: أسرع ٣٠ مرة من عملية (في Solaris)
    • تبديل السياق بين الخيوط: أسرع
  4. قابلية التوسع: يستفيد من معماريات متعددة المعالجات
سؤال: ليش نستخدم خيوط بدل العمليات؟
الجواب: إنشاء أسرع، تبديل سياق أسرع، تواصل أسهل (ذاكرة مشتركة)

🔗 نماذج تعدد الخيوط

١. متعدد إلى واحد
  • خيوط مستخدم كثيرة → خيط نواة واحد
  • تُدار بواسطة مكتبة الخيوط (فعالة)
  • ❌ العملية بأكملها تُحجب إذا انحجب خيط واحد
  • ❌ لا يمكن أن تعمل بالتوازي على معالجات متعددة
  • مثال: Green Threads
٢. واحد إلى واحد
  • كل خيط مستخدم → خيط نواة
  • ✅ توازٍ أكبر (خيط ينحجب، الآخرون يعملون)
  • ✅ يمكن أن تعمل بالتوازي على معالجات متعددة
  • ❌ عبء إنشاء خيوط النواة
  • مثال: ويندوز، لينكس
٣. متعدد إلى متعدد
  • خيوط مستخدم كثيرة → خيوط نواة كثيرة
  • ✅ أفضل الميزات من كلا النموذجين
  • ✅ يمكن أن تعمل بالتوازي
  • ✅ إذا انحجب خيط، يمكن جدولة آخر
  • مثال: Solaris قبل الإصدار ٩

⚡ التزامن مقابل التوازي

التزامن

  • مهام متعددة تتقدم
  • تقاسم الوقت على نواة واحدة
  • تنفيذ متداخل

التوازي

  • مهام متعددة تُنفذ في وقت واحد
  • يحتاج نوى متعددة
  • تنفيذ متزامن حقيقي
أنواع التوازي:
  • توازي البيانات: نفس العملية على مجموعات بيانات مختلفة (مثل معالجة الصور)
  • توازي المهام: مهام مختلفة على نوى مختلفة

٥ جدولة المعالج

📊 معايير الجدولة

المعيار الهدف الصيغة/الوصف
استغلال المعالج تعظيم إبقاء المعالج مشغولاً (٤٠٪-٩٠٪)
الإنتاجية تعظيم عدد العمليات المُنجزة لكل وحدة زمنية
زمن الإنجاز تقليل وقت الإكمال - وقت الوصول
زمن الانتظار تقليل زمن الإنجاز - وقت الانفجار
زمن الاستجابة تقليل أول استجابة - وقت الوصول
زمن الإنجاز = زمن الانتظار + وقت الانفجار
زمن الانتظار = زمن الإنجاز - وقت الانفجار

🎯 خوارزميات الجدولة

١. من يأتي أولاً يُخدم أولاً (FCFS)
  • النوع: غير استباقية
  • الترتيب: حسب وقت وصول العملية
  • ❌ تأثير القافلة (العمليات القصيرة تنتظر الطويلة)
  • ✅ سهلة التنفيذ
٢. الأقصر وظيفةً أولاً (SJF)
  • النوع: يمكن أن تكون استباقية أو غير استباقية
  • الترتيب: أقصر وقت انفجار أولاً
  • ✅ مثالية (أقل متوسط زمن انتظار)
  • ❌ لا يمكن معرفة أوقات الانفجار المستقبلية (يجب تقديرها)
  • ❌ تجويع محتمل للعمليات الطويلة
متوسط التنبؤ بانفجار المعالج التالي:
τ(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=١٤-٥=٩

🔄 استباقي مقابل غير استباقي

غير استباقي

  • العملية تبقى في المعالج حتى تنتهي أو تنتظر
  • أمثلة: 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 ✅ أمثل!

٦ مزامنة العمليات

⚠️ مشكلة القسم الحرج

حالة السباق: عدة عمليات تصل إلى بيانات مشتركة في نفس الوقت، النتيجة تعتمد على ترتيب التنفيذ
قسم حرج: قطعة كود تصل إلى موارد مشتركة
الحل يجب أن يحقق ٣ متطلبات:
  1. الاستبعاد المتبادل: عملية واحدة فقط في القسم الحرج في كل مرة
  2. التقدم: فقط العمليات اللي مو في قسمها المتبقي تقرر من يدخل القسم الحرج بعدين
  3. الانتظار المحدود: حد لعدد مرات دخول الآخرين للقسم الحرج قبل عملية تنتظر

🔒 السيمافورات

السيمافور 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);
٣. مشكلة الفلاسفة
  • ٥ فلاسفة، ٥ أعواد
  • يحتاج عودين ليأكل
  • ❌ جمود إذا كل فيلسوف أخذ العود الأيسر
الحلول:
  • السماح بأقصى ٤ فلاسفة على الطاولة
  • أخذ العودين دفعة واحدة
  • الفلاسفة الفرديون يأخذون اليسار أولاً، الزوجيون يأخذون اليمين أولاً

💀 الجمود

الشروط الضرورية (كلها لازم تتحقق):
  1. الاستبعاد المتبادل: مورد واحد على الأقل غير قابل للمشاركة
  2. الاحتجاز والانتظار: عملية تحتجز موارد وتنتظر المزيد
  3. عدم الاستباق: الموارد لا يمكن أخذها قسرًا
  4. الانتظار الدائري: P1 تنتظر P2، P2 تنتظر P3، ...، Pn تنتظر P1
اختصار: "احتجاز، انتظار، استباق، دائري" ← الشروط الأربعة

٨ إدارة الذاكرة الرئيسية

📍 ربط العناوين

عنوان منطقي مقابل فيزيائي:
  • منطقي (افتراضي): يولده المعالج، يراه البرنامج
  • فيزيائي: الموقع الفعلي في الرام، تراه وحدة الذاكرة
وقت الربط متى قابل لإعادة التموضع؟
وقت الترجمة إذا كان موقع الذاكرة معروفًا مسبقًا لا (كود مطلق)
وقت التحميل عند تحميل البرنامج في الذاكرة نعم (كود قابل لإعادة التموضع)
وقت التنفيذ أثناء تنفيذ البرنامج نعم (يحتاج MMU)

🗺️ وحدة إدارة الذاكرة (MMU)

MMU: جهاز عتادي يرسم العناوين المنطقية إلى فيزيائية
عنوان فيزيائي = مسجل الأساس + عنوان منطقي
مسجلات الأساس والحد:
  • الأساس: عنوان البداية الفيزيائي
  • الحد: حجم مساحة العنوان المنطقي
  • الحماية: إذا (عنوان منطقي >= حد) → خطأ!

🧩 تخصيص الذاكرة المتجاورة

تقسيم ثابت:
  • الذاكرة مقسمة إلى أقسام ثابتة الحجم
  • ❌ تجزؤ داخلي
  • ❌ يحد من تعدد البرمجة
تقسيم متغير:
  • تخصيص ديناميكي بناءً على حجم العملية
  • ❌ تجزؤ خارجي
  • الحل: الضغط (يحتاج إعادة تموضع ديناميكي)
خوارزميات التخصيص:
  • الأول المناسب: خصص أول فجوة مناسبة (الأسرع)
  • الأفضل مناسبة: خصص أصغر فجوة مناسبة (أصغر بقايا)
  • الأسوأ مناسبة: خصص أكبر فجوة (أكبر بقايا)
سابق اختبار: أقسام الذاكرة: ٣٠٠كيلوبايت، ٦٠٠كيلوبايت، ٣٥٠كيلوبايت، ٢٠٠كيلوبايت، ٧٥٠كيلوبايت، ١٢٥كيلوبايت
العمليات: ١١٥كيلوبايت، ٥٠٠كيلوبايت، ٣٥٨كيلوبايت، ٢٠٠كيلوبايت، ٣٧٥كيلوبايت

الأفضل مناسبة:
١١٥كيلوبايت → ١٢٥كيلوبايت (١٠كيلوبايت باقي)
٥٠٠كيلوبايت → ٦٠٠كيلوبايت (١٠٠كيلوبايت باقي)
٣٥٨كيلوبايت → ٧٥٠كيلوبايت (٣٩٢كيلوبايت باقي)
٢٠٠كيلوبايت → ٢٠٠كيلوبايت (٠ باقي)
٣٧٥كيلوبايت → ٣٩٢كيلوبايت ✅ الكل يركب!

📄 التصفح

المفهوم:
  • تقسيم الذاكرة المنطقية إلى صفحات (حجم ثابت)
  • تقسيم الذاكرة الفيزيائية إلى إطارات (نفس الحجم)
  • حجم الصفحة = حجم الإطار (قوة ٢، مثال ٤كيلوبايت)
  • ✅ لا تجزؤ خارجي
  • ❌ تجزؤ داخلي (آخر صفحة)
هيكل العنوان المنطقي:
عنوان منطقي = [رقم الصفحة | إزاحة الصفحة]
إذا كانت مساحة العنوان المنطقي = ٢^م، حجم الصفحة = ٢^ن
رقم الصفحة = م - ن بت
إزاحة الصفحة = ن بت
ترجمة العنوان:
  1. استخرج رقم الصفحة (p) من العنوان المنطقي
  2. ابحث عن رقم الإطار (f) في جدول الصفحات[p]
  3. عنوان فيزيائي = (f × حجم_الإطار) + إزاحة
سابق اختبار: عملية لها ٤ صفحات، حجم الصفحة = ١كيلوبايت
جدول الصفحات: [٠→٥, ١→١٠, ٢→١٣, ٣→٧]
عنوان منطقي = ١٥٠٠

الحل:
حجم الصفحة = ١٠٢٤ بايت
رقم الصفحة = ١٥٠٠ / ١٠٢٤ = ١
الإزاحة = ١٥٠٠ % ١٠٢٤ = ٤٧٦
رقم الإطار = page_table[١] = ١٠
عنوان فيزيائي = ١٠ × ١٠٢٤ + ٤٧٦ = ١٠٧١٦
سابق اختبار: مساحة العنوان المنطقي = ٢٥٦ صفحة، حجم الصفحة = ٤كيلوبايت
الذاكرة الفيزيائية = ٦٤ إطارًا

أ) كم بت في العنوان المنطقي؟
٢٥٦ × ٤كيلوبايت = ٢٥٦ × ٤٠٩٦ = ٢^٨ × ٢^١٢ = ٢^٢٠
الجواب: ٢٠ بت

ب) كم بت في العنوان الفيزيائي؟
٦٤ × ٤كيلوبايت = ٦٤ × ٤٠٩٦ = ٢^٦ × ٢^١٢ = ٢^١٨
الجواب: ١٨ بت

⚡ مخزن الترجمة المؤقت (TLB)

TLB: ذاكرة مخبئية عتادية سريعة لإدخالات جدول الصفحات
  • صغير (٦٤-١٠٢٤ إدخال)
  • بحث متوازي
  • يحتوي ترجمات صفحات حديثة
وقت الوصول الفعال (EAT):
EAT = نسبة_الإصابة × (وقت_TLB + وقت_الذاكرة)
      + (١ - نسبة_الإصابة) × (وقت_TLB + وقت_جدول_الصفحات + وقت_الذاكرة)
سابق اختبار:
وقت الذاكرة = ٥٠ns
وقت TLB = ٢ns
نسبة الإصابة = ٧٥٪

EAT = ٠.٧٥ × (٢ + ٥٠) + ٠.٢٥ × (٢ + ٥٠ + ٥٠)
EAT = ٠.٧٥ × ٥٢ + ٠.٢٥ × ١٠٢
EAT = ٣٩ + ٢٥.٥ = ٦٤.٥ns

🗂️ التقسيم

المفهوم:
  • تقسيم الذاكرة حسب وحدات منطقية (دالة، مصفوفة، مكدس)
  • أقسام ذات حجم متغير
  • رؤية المبرمج للذاكرة
عنوان منطقي:
<رقم القسم، إزاحة>
جدول الأقسام:
  • الأساس: عنوان البداية الفيزيائي
  • الحد: طول القسم
  • الحماية: إذا (الإزاحة >= حد) → خطأ!
إذا الإزاحة < حد:
  عنوان فيزيائي = أساس + إزاحة
وإلا:
  خطأ تجزئة!
مثال: جدول الأقسام
[قسم ٠: أساس=١٢٠٠، حد=١٠٠٠]
[قسم ١: أساس=٤٠٠٠، حد=٦٠٠]
[قسم ٢: أساس=٢٠٠٠، حد=١٤٠٠]

عنوان منطقي <١, ٥٠٠>:
٥٠٠ < ٦٠٠ ✅ صالح
فيزيائي = ٤٠٠٠ + ٥٠٠ = ٤٥٠٠

عنوان منطقي <١, ٦٠٠>:
٦٠٠ >= ٦٠٠ ❌ غير قانوني!

⚖️ التصفح مقابل التقسيم

التصفح

  • صفحات ثابتة الحجم
  • نظرة فيزيائية
  • لا تجزؤ خارجي
  • تجزؤ داخلي
  • غير مرئي للمبرمج

التقسيم

  • أقسام متغيرة الحجم
  • نظرة منطقية
  • تجزؤ خارجي
  • لا تجزؤ داخلي
  • مرئي للمبرمج

٩ الذاكرة الافتراضية

💭 مفهوم الذاكرة الافتراضية

الفوائد:
  • مساحة عنوان منطقي > الذاكرة الفيزيائية
  • برامج أكثر في الذاكرة في نفس الوقت
  • إدخال/إخراج أقل للتحميل
  • بدء تشغيل أسرع للبرامج
التصفح عند الطلب:
  • تحميل الصفحات فقط عند الحاجة
  • مبادل كسول (لا يبادل إلا عند الضرورة)
  • يستخدم بت صالح/غير صالح في جدول الصفحات

💥 خطأ الصفحة

خطأ الصفحة يحدث عندما:
  • عملية تشير إلى صفحة ليست في الذاكرة
  • إدخال جدول الصفحات به بت غير صالح
خطوات معالجة خطأ الصفحة:
  1. تحقق من الجدول الداخلي (PCB) - مرجع صالح أم لا؟
  2. إذا غير صالح → أنهِ العملية
  3. إذا صالح لكن ليس في الذاكرة → أحضره:
    • احصل على إطار فارغ
    • مبادلة الصفحة من القرص إلى الإطار
    • حدث جدول الصفحات (اضبط بت صالح)
    • أعد تشغيل التعليمات
وقت الوصول الفعال (EAT):
EAT = (١ - p) × وقت_الذاكرة + p × وقت_خدمة_خطأ_الصفحة
حيث p = معدل خطأ الصفحة (٠ ≤ p ≤ ١)
سابق اختبار:
وقت الذاكرة = ٢٠٠ns
وقت خدمة خطأ الصفحة = ٨ms = ٨,٠٠٠,٠٠٠ns
معدل خطأ الصفحة = ١/١٠٠٠ = ٠.٠٠١

EAT = (١ - ٠.٠٠١) × ٢٠٠ + ٠.٠٠١ × ٨,٠٠٠,٠٠٠
EAT = ٠.٩٩٩ × ٢٠٠ + ٨,٠٠٠
EAT = ١٩٩.٨ + ٨,٠٠٠ = ٨,١٩٩.٨ns ≈ ٨.٢μs

🔄 خوارزميات استبدال الصفحات

متى نستخدمها: عندما لا توجد إطارات فارغة متاحة
١. FIFO (أولاً يدخل أولاً يخرج)
  • استبدال أقدم صفحة في الذاكرة
  • سهلة التنفيذ
  • ❌ تعاني من شذوذ بيلادي (إطارات أكثر قد تسبب أخطاء أكثر)
٢. الأمثل (OPT)
  • استبدال الصفحة التي لن تُستخدم لأطول وقت
  • ✅ أقل أخطاء صفحة
  • ❌ مستحيل التنفيذ (يحتاج معرفة مستقبلية)
  • يستخدم كمعيار
٣. LRU (الأقل استخدامًا مؤخرًا)
  • استبدال الصفحة التي لم تُستخدم لأطول وقت
  • ✅ تقريب جيد للأمثل
  • ✅ لا يعاني من شذوذ بيلادي
  • التنفيذ: مكدس أو عدادات
سابق اختبار: سلسلة المراجع: ٧,٢,٣,١,٢,٥,٣,٤,٦,٧,٧,١,٠,٥,٤,٦,٢,٣,٠,١
٣ إطارات متاحة

حل LRU:
٧٢٣١٢٥٣٤٦٧٧١٠٥٤٦٢٣٠١
٧٧٧١١١٣٣٣٧٧٧٧٥٥٥٢٢٢١
٢٢٢٢٢٢٤٤٤٤١١١٤٤٤٣٣٣
٣٣٣٥٥٥٦٦٦٦٠٠٠٦٦٦٠٠
إجمالي أخطاء الصفحة: ١٨
مقارنة سريعة: FIFO بسيط لكن عنده بيلادي؛ OPT أمثل لكن مستحيل؛ LRU عملي وجيد

🌀 التخبط

التخبط: العملية تقضي وقتًا في التصفح أكثر من التنفيذ
الأسباب:
  • العملية ليس لديها إطارات كافية
  • درجة عالية من تعدد البرمجة
  • ذاكرة فيزيائية غير كافية
الحلول:
  • تقليل درجة تعدد البرمجة
  • زيادة الذاكرة الفيزيائية (RAM)
  • استخدام خوارزمية استبدال محلية
  • توفير إطارات كافية لكل عملية
سابق اختبار: قياسات النظام:
استخدام المعالج: ١٠٪
قرص التصفح: ٩٧.٧٪

التشخيص: النظام يتخبط!
الحلول: (١) تقليل تعدد البرمجة (٢) زيادة الرام

١١ أنظمة الملفات

📁 مفهوم الملف

الملف: مجموعة مسماة من المعلومات ذات الصلة مخزنة على تخزين ثانوي
سمات الملف:
  • الاسم: شكل قابل للقراءة البشرية
  • المعرف: علامة فريدة (رقم inode)
  • النوع: نص، ثنائي، قابل للتنفيذ
  • الموقع: مؤشر للجهاز والموقع
  • الحجم: حجم الملف الحالي
  • الحماية: أذونات القراءة، الكتابة، التنفيذ
  • الوقت والتاريخ: الإنشاء، آخر وصول، آخر تعديل
عمليات الملف:
  • إنشاء: إيجاد مساحة، إضافة إدخال دليل
  • فتح: تحميل FCB إلى الذاكرة (جدول الملفات المفتوحة)
  • قراءة/كتابة: استخدام مؤشر الملف
  • Seek: إعادة تموضع مؤشر الملف
  • إغلاق: إزالة من جدول الملفات المفتوحة
  • حذف: إزالة إدخال الدليل، تحرير المساحة
  • اقتطاع: حذف المحتويات، الاحتفاظ بالسمات

📂 هيكل الدليل

١. دليل أحادي المستوى
  • كل الملفات في دليل واحد
  • ✅ بسيط
  • ❌ مشكلة التسمية (كل الأسماء يجب أن تكون فريدة)
  • ❌ لا تجميع
٢. دليل ثنائي المستوى
  • دليل رئيسي للملفات + أدلة مستخدمين فرعية
  • ✅ يعزل المستخدمين
  • ✅ بحث فعال
  • ❌ لا قدرة على التجميع
٣. دليل شجري
  • هيكل هرمي (الأكثر شيوعًا)
  • ✅ بحث فعال
  • ✅ قدرة على التجميع
  • ✅ مفهوم الدليل الحالي
  • المسار المطلق: /home/user/file.txt
  • المسار النسبي: ../file.txt
٤. دليل غير دائري
  • يسمح بمشاركة الملفات/الأدلة الفرعية
  • يستخدم روابط (صلبة أو رمزية)
  • ⚠️ مشكلة الحذف (مؤشرات معلقة)

🔐 حماية الملفات

قائمة التحكم بالوصول: تحدد المستخدمين والعمليات المسموح بها
حماية UNIX (rwx):
الفئة الوصف
المالك منشئ الملف
المجموعة مجموعة من المستخدمين يشاركون الوصول
الآخرون كل المستخدمين الآخرين
الأذونات:
  • r (قراءة): قراءة محتويات الملف
  • w (كتابة): كتابة/تعديل الملف
  • x (تنفيذ): تنفيذ الملف
مثال: rwxr-xr-- = المالك: rwx، المجموعة: r-x، الآخرون: r--

🎯 طرق الوصول

وصول تسلسلي

  • السجلات تُعالج بالترتيب
  • مثل شريط
  • تستخدم بواسطة المحررات، المترجمات

وصول مباشر (عشوائي)

  • الوصول لأي سجل مباشرة
  • سجلات ثابتة الطول
  • تستخدم بواسطة قواعد البيانات
وصول مفهرس:
  • ملف فهرس يشير إلى البيانات الفعلية
  • يمكن أن يكون له فهارس متعددة المستويات
  • مثال: ISAM

مرجع سريع وصيغ

📐 صيغ أساسية

التصفح:
رقم الصفحة = عنوان منطقي / حجم الصفحة
إزاحة الصفحة = عنوان منطقي % حجم الصفحة
عنوان فيزيائي = (رقم الإطار × حجم الإطار) + إزاحة

بتات العنوان المنطقي = log₂(صفحات × حجم الصفحة)
بتات العنوان الفيزيائي = log₂(إطارات × حجم الإطار)
TLB وقت الوصول الفعال:
EAT = h × (وقت_TLB + وقت_الذاكرة) + (١-h) × (وقت_TLB + وقت_جدول_الصفحات + وقت_الذاكرة)
حيث h = نسبة الإصابة
EAT مع خطأ الصفحة:
EAT = (١-p) × وقت_الذاكرة + p × وقت_خدمة_خطأ_الصفحة
حيث p = معدل خطأ الصفحة
الجدولة:
زمن الإنجاز = وقت الإكمال - وقت الوصول
زمن الانتظار = زمن الإنجاز - وقت الانفجار
زمن الاستجابة = أول استجابة - وقت الوصول
الوصول للقرص:
وقت الوصول = وقت البحث + وقت الدوران + وقت النقل

🎯 نصائح سريعة للاختبارات

عملية مقابل خيط: عملية = ثقيلة، ذاكرة منفصلة؛ خيط = خفيف، ذاكرة مشتركة
قيم إرجاع fork(): ٠ للابنة، PID الابنة للأم، -١ عند الخطأ
بت الوضع: ٠ = وضع نواة، ١ = وضع مستخدم
تجزؤ خارجي: تقسيم متغير، تقسيم
تجزؤ داخلي: تقسيم ثابت، تصفح
حجم الصفحة = حجم الإطار (دايمًا متساويان!)
شذوذ بيلادي: فقط FIFO يعاني منه (ليس LRU أو الأمثل)
شروط الجمود (كلها مطلوبة): استبعاد متبادل، احتجاز وانتظار، عدم استباق، انتظار دائري
خوارزميات استباقية: RR، SRTF، أولويات استباقية
خوارزميات غير استباقية: FCFS، SJF، أولويات غير استباقية

🔢 تحويلات شائعة

الوحدة القيمة
١ كيلوبايت ١٠٢٤ بايت = ٢^١٠
١ ميجابايت ١٠٢٤ كيلوبايت = ٢^٢٠ بايت
١ جيجابايت ١٠٢٤ ميجابايت = ٢^٣٠ بايت
١ ملي ثانية ١,٠٠٠ ميكروثانية = ١,٠٠٠,٠٠٠ نانوثانية
١ ميكروثانية ١,٠٠٠ نانوثانية

✅ أخطاء شائعة تتجنبها في الاختبار

خطأ: الاعتقاد أن حجم الصفحة ≠ حجم الإطار
صحيح: حجم الصفحة دايمًا يساوي حجم الإطار
خطأ: fork() يرجع PID الابنة للابنة
صحيح: fork() يرجع ٠ للابنة، PID الابنة للأم
خطأ: الخيوط تشارك المكدس
صحيح: كل خيط له مكدسه الخاص؛ يشاركون الكود، البيانات، الكومة
خطأ: زمن الانتظار يشمل وقت الانفجار
صحيح: زمن الانتظار = زمن الإنجاز - وقت الانفجار
خطأ: التصفح يسبب تجزؤًا خارجيًا
صحيح: التصفح يزيل التجزؤ الخارجي، لكن يسبب تجزؤًا داخليًا

📝 قائمة المراجعة النهائية

قبل الاختبار، تأكد أنك تستطيع:
  • ✅ حساب رقم الصفحة والإزاحة من عنوان منطقي
  • ✅ تحويل عنوان منطقي إلى فيزيائي باستخدام جدول الصفحات
  • ✅ حساب وقت الوصول الفعال مع TLB
  • ✅ رسم مخططات جانت لكل خوارزميات الجدولة
  • ✅ حساب زمن الانتظار وزمن الإنجاز
  • ✅ تتبع تنفيذ fork() وحساب عدد العمليات المنشأة
  • ✅ تنفيذ منتج-مستهلك بالسيمافورات
  • ✅ تنفيذ استبدال الصفحات (FIFO، LRU، الأمثل)
  • ✅ حساب البتات اللازمة للعناوين المنطقية/الفيزيائية
  • ✅ فهم الفرق بين العملية والخيط
  • ✅ معرفة متى تستخدم كل خوارزمية تخصيص (أول مناسب، أفضل مناسب، أسوأ مناسب)
  • ✅ تحديد شروط الجمود
  • ✅ فهم فوائد الذاكرة الافتراضية وأخطاء الصفحة