প্রসেস কন্ট্রোল ব্লক (PCB) ও কনটেক্সট সুইচিং
এই পাঠে যা শিখবেন
- PCB-তে ঠিক কী কী তথ্য সংরক্ষিত থাকে এবং কেন প্রতিটি প্রসেসের নিজস্ব একটি PCB দরকার
- কনটেক্সট সুইচ ঠিক কী করে — সেভ ও লোডের সঠিক ক্রম
- কেন কনটেক্সট সুইচ "বিনামূল্যে" নয় — এটি কেন খাঁটি ওভারহেড
- Python দিয়ে দুটি প্রসেসের মধ্যে একটি বাস্তব কনটেক্সট-সুইচ সিমুলেশন, ফিরে গিয়ে যাচাই করা রেজিস্টার স্টেট ঠিকভাবে সংরক্ষিত ছিল কি না
১ · PCB — OS-এর "প্রসেস ফাইল"
PCB (Process Control Block)Process Control BlockOS-এর ডেটা স্ট্রাকচার যা একটি নির্দিষ্ট প্রসেস পরিচালনার জন্য প্রয়োজনীয় সব তথ্য (স্টেট, রেজিস্টার, প্রায়োরিটি, মেমরি তথ্য, খোলা ফাইল) ধরে রাখে। হলো OS-এর একটি ডেটা স্ট্রাকচার — প্রতিটি প্রসেসের জন্য একটি করে — যেখানে সেই প্রসেস পরিচালনার জন্য প্রয়োজনীয় প্রায় সবকিছু থাকে: L05-এর প্রসেস স্টেট, প্রোগ্রাম কাউন্টার (পরবর্তী কোন নির্দেশ চালাতে হবে), CPU রেজিস্টারের মান, CPU শিডিউলিং তথ্য (প্রায়োরিটি — M3-এ বিস্তারিত), মেমরি ম্যানেজমেন্ট তথ্য, এবং I/O স্ট্যাটাস তথ্য। সব প্রসেসের PCB একসাথে মিলে OS-এর অভ্যন্তরীণ "প্রসেস টেবিল" গঠন করে — OS এই টেবিল দেখেই জানে সিস্টেমে এই মুহূর্তে কোন কোন প্রসেস আছে এবং প্রতিটির অবস্থা কী।
২ · কনটেক্সট সুইচ কী
কনটেক্সট সুইচContext SwitchOS যখন CPU-কে এক প্রসেস চালানো থেকে সরিয়ে আরেকটি প্রসেস চালানোয় নিয়ে যায় — বর্তমান প্রসেসের রেজিস্টার স্টেট সেভ করে এবং পরবর্তী প্রসেসের স্টেট লোড করে। ঘটে যখন OS CPU-কে একটি চলমান প্রসেস থেকে সরিয়ে অন্য একটি প্রসেসে নিয়ে যায়। এই প্রক্রিয়ায় দুটি ধাপ অবশ্যই সঠিক ক্রমে ঘটতে হবে — প্রথমে বর্তমান (আউটগোয়িং) প্রসেসের CPU রেজিস্টার স্টেট তার নিজের PCB-তে সেভ করতে হবে (নাহলে সেই কাজ চিরতরে হারিয়ে যাবে), তারপর পরবর্তী (ইনকামিং) প্রসেসের PCB থেকে তার আগে সেভ করা রেজিস্টার স্টেট CPU-তে লোড করতে হবে। এই সেভ/লোড ছাড়া CPU জানবেই না ইনকামিং প্রসেসটি ঠিক কোথায় থেমে ছিল।
৩ · কনটেক্সট সুইচ কেন "বিনামূল্যে" নয়
কনটেক্সট সুইচের সময় CPU কোনো ব্যবহারকারী প্রোগ্রামের জন্য দরকারি কাজ করছে না — এটি শুধু রেজিস্টার সেভ/লোড করছে। এই সময়টুকু সম্পূর্ণ ওভারহেড — কোনো প্রসেসের প্রকৃত অগ্রগতি হচ্ছে না। তাই যত ঘন ঘন কনটেক্সট সুইচ হবে, তত বেশি CPU সময় এই "হিসাব-নিকাশে" ব্যয় হবে, প্রকৃত কাজে কম। এই সরাসরি সম্পর্কই M3-এর Round Robin শিডিউলিংয়ের টাইম-কোয়ান্টাম বেছে নেওয়ার সবচেয়ে গুরুত্বপূর্ণ ট্রেড-অফ — কোয়ান্টাম খুব ছোট হলে বেশি সুইচ হয় (বেশি ওভারহেড), খুব বড় হলে রেসপন্সিভনেস কমে যায়।
৪ · একটি কনটেক্সট-সুইচ সিমুলেশন
নিচের কোডে দুটি প্রসেসের PCB এবং একটি context_switch() ফাংশন তৈরি করে দেখানো হলো P1 থেকে P2-তে
সুইচ করা, তারপর আবার P2 থেকে P1-এ ফিরে আসা — এবং যাচাই করা হলো P1-এর রেজিস্টার স্টেট এই দুই সুইচের মধ্যেও
অবিকৃত ছিল কি না।
# PCB ও কনটেক্সট সুইচ সিমুলেশন -- সিমুলেটেড, বাস্তব কোনো CPU রেজিস্টার নয়
pcb_table = {
"P1": {"pid": 1, "state": "Running", "priority": 2, "saved_registers": None},
"P2": {"pid": 2, "state": "Ready", "priority": 1, "saved_registers": None},
}
def context_switch(cpu_registers, outgoing_pcb, incoming_pcb):
# ধাপ ১: বর্তমান (আউটগোয়িং) প্রসেসের রেজিস্টার স্টেট তার নিজের PCB-তে সেভ করা
outgoing_pcb["saved_registers"] = dict(cpu_registers)
outgoing_pcb["state"] = "Ready"
# ধাপ ২: ইনকামিং প্রসেসের PCB থেকে তার সেভ করা রেজিস্টার স্টেট লোড করা
incoming_pcb["state"] = "Running"
return dict(incoming_pcb["saved_registers"])
# শুরুতে P1 চলছে, CPU রেজিস্টারে তার state আছে
cpu_registers = {"PC": 1000, "ACC": 42, "SP": 9000}
pcb_table["P1"]["saved_registers"] = dict(cpu_registers)
# P2-এর আগে সেভ করা রেজিস্টার (এখনও কখনো চলেনি ধরে নিলে তার শুরুর মান)
pcb_table["P2"]["saved_registers"] = {"PC": 2000, "ACC": 0, "SP": 8000}
print("সুইচ ১: P1 -> P2")
cpu_registers = context_switch(cpu_registers, pcb_table["P1"], pcb_table["P2"])
print("CPU রেজিস্টার এখন (P2-এর):", cpu_registers)
print("P1-এর PCB-তে সেভ হওয়া রেজিস্টার:", pcb_table["P1"]["saved_registers"])
# P2 চলাকালীন কিছু কাজ করলো, তার রেজিস্টার বদলে গেলো
cpu_registers["ACC"] = 99
cpu_registers["PC"] = 2050
print("\nসুইচ ২: P2 -> P1 (ফিরে যাওয়া)")
cpu_registers = context_switch(cpu_registers, pcb_table["P2"], pcb_table["P1"])
print("CPU রেজিস্টার এখন (P1-এর):", cpu_registers)
print("P2-এর PCB-তে সেভ হওয়া রেজিস্টার:", pcb_table["P2"]["saved_registers"])
print("\nনিশ্চিতকরণ: P1-এর রেজিস্টার অবস্থা সঠিকভাবে সংরক্ষিত ছিল কি?",
cpu_registers == {"PC": 1000, "ACC": 42, "SP": 9000})
saved_registers কেউ স্পর্শই করেনি (P2 চলাকালীন
শুধু cpu_registers ভেরিয়েবল বদলেছে, P1-এর PCB নয়) — তাই যখন P1-এ ফিরে আসা হলো, তার ঠিক আগের
অবস্থাই (PC=1000, ACC=42, SP=9000) নিখুঁতভাবে ফিরে এলো। এটিই কনটেক্সট সুইচের মূল প্রতিশ্রুতি।
PCB ও কনটেক্সট সুইচ একসাথে একটি বিভ্রম তৈরি করে — প্রতিটি প্রসেস মনে করে সে একাই, বাধাহীনভাবে চলছে, যদিও বাস্তবে CPU বারবার তার থেকে সরে গিয়ে অন্য প্রসেসে যাচ্ছে এবং ফিরে আসছে। L07 দেখাবে এই প্রসেসগুলো আসলে কীভাবে তৈরি ও শেষ হয়, এবং একটি টার্মিনেটেড প্রসেস কীভাবে সাময়িকভাবে একটি "জম্বি" হিসেবে টেবিলে থেকে যেতে পারে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ যদি কনটেক্সট সুইচের সময় "সেভ" ধাপটি "লোড" ধাপের আগে না হয়ে পরে করা হতো, তাহলে কী সমস্যা হতো?
যদি আগে লোড করা হতো (ইনকামিং প্রসেসের রেজিস্টার CPU-তে বসিয়ে দেওয়া), তাহলে আউটগোয়িং প্রসেসের এখনো-না-সেভ-করা
বর্তমান রেজিস্টার স্টেট চিরতরে হারিয়ে যেত — CPU রেজিস্টার ওভাররাইট হয়ে যাওয়ার পর আর সেই ডেটা ফিরে
পাওয়ার উপায় নেই। এই কারণেই ক্রম কঠোরভাবে "প্রথমে সেভ, তারপর লোড" হতে হবে — উপরের কোডেও
context_switch() ফাংশনে ঠিক এই ক্রমেই কাজ দুটি হয়েছে।
প্র ০২ PCB-তে "CPU শিডিউলিং তথ্য" (যেমন প্রায়োরিটি) কেন রাখা দরকার — এটি কি রেজিস্টার স্টেটের সাথে সম্পর্কিত নয়?
প্রায়োরিটি রেজিস্টার স্টেটের অংশ নয় (এটি হার্ডওয়্যার-স্তরের CPU ডেটা নয়), কিন্তু OS-এর শিডিউলারের (M3) জন্য অপরিহার্য — পরবর্তী কোন প্রসেসকে CPU দেওয়া হবে তা ঠিক করতে শিডিউলারকে প্রতিটি Ready প্রসেসের প্রায়োরিটি জানতে হয়। যেহেতু PCB ইতিমধ্যেই "প্রতি প্রসেসের সব প্রাসঙ্গিক তথ্যের একক জায়গা," প্রায়োরিটির মতো শিডিউলিং-সম্পর্কিত তথ্যও যৌক্তিকভাবে সেখানেই রাখা হয়, রেজিস্টার স্টেটের পাশাপাশি একটি আলাদা ফিল্ড হিসেবে।
প্র ০৩ উপরের কোড সেলে "নিশ্চিতকরণ" লাইনটি কীভাবে প্রমাণ করছে যে কনটেক্সট সুইচ সঠিকভাবে কাজ করেছে?
সুইচ ১-এর পর P2 চলাকালীন cpu_registers-এ ইচ্ছাকৃতভাবে পরিবর্তন আনা হয়েছিল
(ACC=99, PC=2050) — যদি P1-এর আসল অবস্থা কোনোভাবে P2-এর পরিবর্তনের দ্বারা প্রভাবিত হতো,
তাহলে সুইচ ২-এর পর ফিরে পাওয়া রেজিস্টার আসল {"PC": 1000, "ACC": 42, "SP": 9000}-এর সাথে
মিলত না। শেষ লাইনে সরাসরি এই দুটি তুলনা করে True/False প্রিন্ট করে দেখানো
হয়েছে যে P1-এর PCB সঠিকভাবে তার নিজস্ব, অবিকৃত অবস্থা ধরে রেখেছিল।
অনুশীলন
-
চিন্তা করুন: আপনার কম্পিউটারে একসাথে ৫০টির বেশি প্রসেস চলছে এমন একটি অবস্থা কল্পনা করুন — একটি একক-কোর CPU সবগুলোর PCB নিয়ে কী করবে বলে মনে করেন?
সবগুলো প্রসেসের PCB OS-এর process table-এ থাকবে, কিন্তু যেকোনো মুহূর্তে মাত্র একটি প্রসেসের রেজিস্টার স্টেট আসল CPU-তে লোড থাকবে (Running স্টেট) — বাকি প্রায় ৪৯টির (Ready বা Waiting) রেজিস্টার স্টেট তাদের নিজস্ব PCB-তে সেভ করা অবস্থায় থাকবে। শিডিউলার (M3) দ্রুত, ঘন ঘন কনটেক্সট সুইচ করে একে একে প্রতিটিকে সংক্ষিপ্ত সময়ের জন্য CPU দেবে, যা মানুষের চোখে "সবগুলো একসাথে চলছে" বলে মনে হয়।
-
পরীক্ষা করুন: উপরের কোড সেলে সুইচ ২-এর আগে
pcb_table["P1"]["saved_registers"]["ACC"] = 999লাইন যোগ করে (P1-এর PCB সরাসরি বদলে দিয়ে) Run চাপুন — শেষ "নিশ্চিতকরণ" লাইনটি এখন কী প্রিন্ট করবে?এখন সুইচ ২-এ
context_switch()P1-এর PCB থেকে{"PC": 1000, "ACC": 999, "SP": 9000}লোড করবে (কারণ আমরা সরাসরি PCB-র মধ্যেইACCবদলে দিয়েছি), যা মূল{"PC": 1000, "ACC": 42, "SP": 9000}-এর সাথে মেলে না — তাই নিশ্চিতকরণ লাইনটি এবারFalseপ্রিন্ট করবে। এটি দেখায় যে PCB নিজেই যদি বাইরে থেকে পরিবর্তিত হয়, কনটেক্সট সুইচ সেই (সম্ভবত অনিচ্ছাকৃত) পরিবর্তনসহই ডেটা লোড করবে — সুইচ ফাংশনটি নিজে কোনো "সঠিকতা" যাচাই করে না।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরবর্তী পাঠ — প্রসেস ক্রিয়েশন ও টার্মিনেশন L07 নতুন PCB ঠিক কীভাবে তৈরি হয়, এবং একটি প্রসেস শেষ হওয়ার পর কী ঘটে (জম্বি ও অরফান প্রসেস)।
- CPU শিডিউলিং মডিউল M3 প্রিভিউ কনটেক্সট-সুইচ ওভারহেড ও শিডিউলিং কোয়ান্টামের ট্রেড-অফ বিস্তারিতভাবে দেখুন।
- আগের পাঠে ফিরে যান — প্রসেস কনসেপ্ট ও প্রসেস স্টেট L05 রিভিশনের জন্য।