Ada দিয়ে রিয়েল-টাইম সিস্টেম প্রোগ্রামিং ── priority, period ও execution time নিয়ন্ত্রণ বাস্তবে
· হালনাগাদের তারিখ: · Go Komura · Ada, RealTime, Ravenscar, CeilingLocking, Tasking, Scheduling, PriorityInversion, ProgrammingLanguage, রিয়েল-টাইম, উচ্চ নির্ভরযোগ্যতা
1. সূচনা ── Ada ও রিয়েল-টাইমের গভীর সম্পর্ক
আগের নিবন্ধ “Ada-তে নিরাপদ concurrency“-এ Ada-এর টাস্ক ও protected object দিয়ে নিরাপদ concurrency-এর ভিত্তি ব্যাখ্যা করেছি। এবার তারই ধারাবাহিকতায় আরও কঠোরভাবে সীমিত এলাকা—রিয়েল-টাইম সিস্টেম—নিয়ে এগোব।
রিয়েল-টাইম সিস্টেমে “সঠিকতা” মানে শুধু লজিক্যাল computation-এর ফল সঠিক হওয়া নয়, সেই ফল সময়সীমার মধ্যে পাওয়াও। এক মিলিসেকেন্ড দেরিতে আসা সঠিক উত্তর ভুল উত্তরের মতোই বিপজ্জনক।
এই চাহিদার জবাবে Ada ভাষার স্পেসিফিকেশনের Annex D (Real-Time Systems) হিসেবে মানক করা একটি পূর্ণাঙ্গ রিয়েল-টাইম ফিচারসেট দেয়। এটা “লাইব্রেরি দিয়ে পরে জুড়ে দেওয়া” নয়, ভাষার runtime-এই বসানো রিয়েল-টাইম গ্যারান্টি।
Ada-এর রিয়েল-টাইম ফিচার (Annex D):
- টাস্ক priority ও preemption (FIFO_Within_Priorities)
- Ceiling_Locking protocol (priority inversion প্রতিরোধ)
- delay until দিয়ে absolute time-এর periodic execution
- Ravenscar profile (safety-critical subset)
- timing event (polling ছাড়া সময়মতো জাগানো)
- execution time monitoring (Ada.Execution_Time)
- multi-period scheduling
এই নিবন্ধে এগুলো আটটি ব্যবহারিক কোড উদাহরণ দিয়ে ধাপে ধাপে ব্যাখ্যা করব। প্রতিটি স্নিপেট আলাদা উদাহরণ হিসেবে ধরা যায়, তবে একাধিক compilation unit থাকা 04/05 উদাহরণ gnatchop দিয়ে ভাগ করে তারপর gnatmake করতে হয়।
উদ্দিষ্ট পাঠক ও পূর্বজ্ঞান: আগের নিবন্ধে আলোচনা করা টাস্ক, rendezvous ও protected object-এর ভিত্তি যারা জানেন, তাদের ধরে নেওয়া হয়েছে। Embedded ডিভাইস বা উচ্চ-নির্ভরযোগ্য সিস্টেমের কন্ট্রোল সফটওয়্যারে আগ্রহী ডেভেলপারদের জন্য; Ada ব্যাকরণের পরিচিতি এখানে নেই।
যাচাইয়ের পরিবেশ: এই নিবন্ধের আটটি উদাহরণ GNAT 13.3.0 (Ubuntu 24.04, x86-64)-এ বিল্ড হয় কি না দেখা হয়েছে। যেসব উদাহরণে রান আউটপুট আছে (অধ্যায় 3 ও 5), সেগুলোও একই পরিবেশে নেওয়া। Priority ও preemption বাস্তবে কীভাবে কাজ করে তা OS ও GNAT runtime-এর উপর নির্ভর করে (অধ্যায় 12), তাই আউটপুটের খুঁটিনাটি পরিবেশভেদে বদলাতে পারে।
এই নিবন্ধের কোড খণ্ড অধ্যায় অনুযায়ী ফাইলে সাজানো রেফারেন্স সংগ্রহ হিসেবে GitHub-এ প্রকাশিত।
ada-real-time-systems - komurasoft-blog-samples (GitHub)
এই নিবন্ধের জ্ঞান মানচিত্র
Ada-এর ভাষা স্পেসিফিকেশন Annex D task অগ্রাধিকারের উপর ভিত্তি করা FIFO_Within_Priorities, protected object-এ স্বয়ংক্রিয়ভাবে সিলিং অগ্রাধিকার বরাদ্দ করা Ceiling_Locking প্রোটোকল, cumulative drift আটকানো delay until দিয়ে পিরিয়ডিক চালনা, static analysis সহজ করা Ravenscar প্রোফাইল, পোলিং ছাড়া timing events, আর task অনুযায়ী execution time পরিমাপ পর্যন্ত ভাষার রানটাইমেই বসিয়েছে। Ceiling_Locking ১৯৯৭ সালে Mars Pathfinder-এ সত্যি ঘটে যাওয়া এবং মহাকাশযানকে বারবার রিসেট করানো priority inversion-কে, protected object-এ ঢোকা task-কে সিলিং অগ্রাধিকারে স্বয়ংক্রিয়ভাবে তুলে দিয়ে আটকায়। Ravenscar প্রোফাইল আপেক্ষিক delay বা select স্টেটমেন্ট ইত্যাদি নিষিদ্ধ করে Ada-এর task-কে static timing analysis সহজ এমন সাবসেটে সীমাবদ্ধ করে, আর GNAT-এ gnat.adc ফাইলে pragma লিখে সক্রিয় করা হয়। তবে অগ্রাধিকারের বাস্তব ম্যাপিং OS ও GNAT রানটাইমের উপর নির্ভর করে।
flowchart LR
accTitle: Ada রিয়েল-টাইম সিস্টেম প্রোগ্রামিংয়ের জ্ঞান মানচিত্র
accDescr: Ada Annex D যেভাবে অগ্রাধিকারভিত্তিক ডিসপ্যাচ · Ceiling_Locking · delay until · Ravenscar প্রোফাইল · timing events · execution time পরিমাপকে task ও protected object-এর উপর বসায়, এবং Ceiling_Locking Mars Pathfinder-এ যে ধরনের priority inversion ঘটেছিল তা কীভাবে আটকায় তা দেখানো চিত্র
ada_annex_d["Annex D (Ada-এর রিয়েল-টাইম সিস্টেম স্ট্যান্ডার্ড)"]
ceiling_locking["Ceiling_Locking প্রোটোকল"]
fifo_within_priorities["FIFO_Within_Priorities"]
ada_delay_until["delay until (পরম সময়ের delay)"]
ravenscar_profile["Ravenscar প্রোফাইল"]
ada_timing_events["timing events (Ada.Real_Time.Timing_Events)"]
ada_execution_time["Ada.Execution_Time (execution time পরিমাপ)"]
ada_task["Ada-এর task (concurrency)"]
protected_object["প্রোটেক্টেড অবজেক্ট (protected object)"]
gnat["GNAT"]
priority_inversion["প্রায়োরিটি ইনভার্সন (priority inversion)"]
mars_pathfinder_priority_inversion["Mars Pathfinder-এর প্রায়োরিটি ইনভার্সন দুর্ঘটনা"]
ada_relative_delay["আপেক্ষিক delay (delay স্টেটমেন্ট)"]
cumulative_drift["পিরিয়ডিক চালনার cumulative drift"]
ada_annex_d -->|"ব্যবহার করে"| fifo_within_priorities
ada_annex_d -->|"ব্যবহার করে"| ceiling_locking
ada_annex_d -->|"ব্যবহার করে"| ada_delay_until
ada_annex_d -->|"ব্যবহার করে"| ravenscar_profile
ada_annex_d -->|"ব্যবহার করে"| ada_timing_events
ada_annex_d -->|"ব্যবহার করে"| ada_execution_time
ada_annex_d -->|"পূর্বশর্ত"| ada_task
ada_annex_d -.->|"পূর্বশর্ত"| protected_object
ada_annex_d -.->|"পূর্বশর্ত"| gnat
ceiling_locking -->|"প্রতিরোধ করে"| priority_inversion
priority_inversion -->|"কারণ হতে পারে"| mars_pathfinder_priority_inversion
ravenscar_profile -->|"পূর্বশর্ত"| ada_task
ravenscar_profile -->|"পূর্বশর্ত"| fifo_within_priorities
ravenscar_profile -->|"পূর্বশর্ত"| ceiling_locking
ravenscar_profile -.->|"দিয়ে কনফিগার"| gnat
ada_relative_delay -->|"কারণ হতে পারে"| cumulative_drift
ada_delay_until -->|"প্রতিরোধ করে"| cumulative_drift
ada_relative_delay -->|"ব্যবহার নিরুৎসাহিত"| ravenscar_profile
ada_timing_events -->|"ব্যবহার করে"| ceiling_locking
ada_timing_events -->|"ব্যবহার করে"| protected_object
ada_execution_time -->|"পূর্বশর্ত"| ada_task
চিত্রে, টানা রেখা সবসময় সত্য এমন সম্পর্ককে এবং ভাঙা রেখা শর্তসাপেক্ষ সম্পর্ককে নির্দেশ করে (শর্তগুলো বিস্তারিত পাতায় প্রতিটি সম্পর্কের ব্যাখ্যায় আছে)। সম্পর্কের সম্পূর্ণ তালিকা (মোট 21, প্রমাণ ও নিশ্চয়তার মাত্রাসহ) এবং প্রধান ধারণাগুলোর সংজ্ঞা জ্ঞান মানচিত্রের বিস্তারিত পাতায় সংগ্রহ করা আছে (জাপানি ভাষায়)। তথ্য: JSON-LD / Turtle
2. রিয়েল-টাইম সিস্টেম কী
প্রথমে পরিভাষা গুছিয়ে নেই।
| ধারণা | ব্যাখ্যা |
|---|---|
| Hard real-time | Deadline ছাড়িয়ে যাওয়া মানে সিস্টেমের মারাত্মক ব্যর্থতা (ফ্লাইট কন্ট্রোল, এয়ারব্যাগ, পেসমেকার) |
| Soft real-time | Deadline ছাড়ানো অবাঞ্ছিত, তবে বিরল ছাড়িয়ে যাওয়া সহনীয় (ভিডিও স্ট্রিমিং, গেম) |
| Deadline | যে absolute time-এ টাস্ক শেষ হতেই হবে |
| Period | টাস্ক বারবার চালু হওয়ার সময়ের ব্যবধান |
| WCET (Worst-Case Execution Time) | টাস্কের সবচেয়ে খারাপ execution time |
| Jitter | Periodic চালানোর তারতম্য |
| Schedulability | “সেই টাস্ক সেট সব deadline মেনে চালানো যায় কি না” সেই বৈশিষ্ট্য। কাগজে এটা যাচাই করার কাজই schedulability analysis (response-time analysis ইত্যাদি) |
| Ravenscar profile | Ada-এর টাস্ক ফিচারকে static analysis-সহজ subset-এ সীমিত করার নিয়ম। নাম এসেছে যে ব্রিটিশ গ্রামে খসড়া বৈঠক হয়েছিল, সেই Ravenscar থেকে (অধ্যায় 6) |
রিয়েল-টাইম সিস্টেম ডিজাইনে প্রতিটি টাস্কের জন্য “WCET <= deadline” একটি গুরুত্বপূর্ণ প্রয়োজনীয় শর্ত। তবে শুধু এতে পুরো সিস্টেমের deadline পূরণ নিশ্চিত হয় না। Blocking time, priority বণ্টন, jitter, interrupt, আর runtime ও OS-এর আচরণ ধরে response-time analysis আলাদাভাবে লাগে। কাজে সাধারণত মার্জিন রাখতে WCET < deadline লক্ষ্য করা হয়। Ada-এর রিয়েল-টাইম ফিচার সেই বিশ্লেষণ সহজ করে, ভাষার স্তরেই একটি predictable execution model দেয়।
flowchart LR
accTitle: রিয়েল-টাইম প্রয়োজনীয়তা ও schedulability বিশ্লেষণ
accDescr: Hard ও soft real-time, deadline, period, WCET, jitter এবং Ada Annex D-এর mechanism কীভাবে schedulability বিশ্লেষণে যুক্ত হয় তা দেখায়।
HRT[হার্ড রিয়েল-টাইম] -->|সময়সীমার মধ্যে না পৌঁছানো = মারাত্মক ব্যর্থতা| Examples[ফ্লাইট কন্ট্রোল<br/>এয়ারব্যাগ<br/>পেসমেকার]
SRT[সফট রিয়েল-টাইম] -->|বিরল ছাড়িয়ে যাওয়া সহনীয়| Examples2[ভিডিও স্ট্রিমিং<br/>গেম<br/>UI]
Ada[Ada Annex D<br/>predictability সমর্থন করা mechanism] --> Mechanism[FIFO_Within_Priorities<br/>Ceiling_Locking<br/>delay until]
subgraph Requirements[রিয়েল-টাইম প্রয়োজনীয়তা]
D[Deadline<br/>শেষ হওয়ার absolute time]
P[Period<br/>পুনরাবৃত্তির ব্যবধান]
W[WCET<br/>সবচেয়ে খারাপ execution time]
J[Jitter<br/>period-এর তারতম্য]
end
D --> Analysis[Schedulability analysis]
P --> Analysis
W --> Analysis
J --> Analysis
HRT --> Analysis
SRT --> Analysis
Mechanism --> Analysis
Analysis --> Constraint[প্রয়োজনীয় শর্ত: WCET <= deadline<br/>পর্যাপ্ততা response-time analysis-এ যাচাই]
রিয়েল-টাইম সিস্টেমের সবচেয়ে বিপজ্জনক ঘটনাগুলোর একটি priority inversion। এই সমস্যা 1997 সালে Mars Pathfinder-এ সত্যি ঘটেছিল, আর প্রোব বারবার reset হচ্ছিল।
sequenceDiagram
accTitle: Priority inversion কীভাবে ঘটে
accDescr: নিম্ন priority টাস্ক lock ধরে রাখার সময় মধ্যম priority টাস্ক তাকে preempt করলে উচ্চ priority টাস্ক অনির্দিষ্টকাল block হয়ে যায়।
participant S as Scheduler
participant L as নিম্ন priority টাস্ক
participant H as উচ্চ priority টাস্ক
participant M as মধ্যম priority টাস্ক
participant R as শেয়ারড রিসোর্স
L->>R: Lock নেয়
activate L
Note over L: Critical section চলছে
Note over S,L: H জেগে ওঠায় scheduler L-কে থামায়
deactivate L
activate H
H->>R: Lock নেওয়ার চেষ্টা করে
Note over H: Lock-এর অপেক্ষায় block! (L ধরে আছে)
deactivate H
Note over S,L: H lock-এর অপেক্ষায়, তাই L আবার চলে
activate L
Note over L: Lock ছাড়ার দিকে এগোচ্ছে...
Note over S,L: M জেগে ওঠায় scheduler L-কে থামায়
deactivate L
activate M
Note over L: L lock ছাড়তে পারছে না
Note over M: M চলতে থাকে (Hও Lও নড়তে পারে না)
Note over H: [priority inversion] উচ্চ priority অনির্দিষ্টকাল block
deactivate M
নিম্ন priority টাস্ক lock ধরে রাখার সময় মধ্যম priority টাস্ক তাকে preempt করে, আর উচ্চ priority টাস্ক অনির্দিষ্টকাল block হয়ে যায়। Mars Pathfinder-এ যা সত্যি করা হয়েছিল তা VxWorks-এর priority inheritance চালু করা; Ada একই ধরনের সমস্যায় অন্য পদ্ধতি Ceiling_Locking ভাষার ফিচার হিসেবে দেয়।
3. টাস্ক priority-এর ভিত্তি ── FIFO_Within_Priorities
FIFO_Within_Priorities হলো Ada Annex D-এ নির্দিষ্ট করা যায় এমন মানক priority-ভিত্তিক dispatching policy। Policy না লিখলে ডিফল্ট আচরণ implementation-defined, তবে GNAT অনেক টার্গেটে এই ধারার policy ব্যবহার করে। একই priority-র ভিতরে FIFO (first-in, first-out) দিয়ে চলে, আর উচ্চতর priority-র টাস্ক নিম্নতর priority-র টাস্ককে preempt করে।
-- 01_task_priority.ada
-- টাস্ক priority ও FIFO_Within_Priorities-এর মৌলিক রূপ
-- configuration pragma context clause-এর আগে রাখতে হয়
pragma Task_Dispatching_Policy (FIFO_Within_Priorities);
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
procedure Task_Priority_Demo is
task High_Priority_Task is
pragma Priority (Priority'Last);
pragma Storage_Size (4 * 1024);
end High_Priority_Task;
task Low_Priority_Task is
pragma Priority (Priority'First);
pragma Storage_Size (4 * 1024);
end Low_Priority_Task;
task body High_Priority_Task is
begin
Put_Line ("[T=0.0s] High priority task started");
delay until Clock + Milliseconds (100);
Put_Line ("[T=0.1s] High priority task completed");
end High_Priority_Task;
task body Low_Priority_Task is
begin
Put_Line ("[T=0.0s] Low priority task started");
delay until Clock + Milliseconds (500);
Put_Line ("[T=0.5s] Low priority task completed");
end Low_Priority_Task;
begin
Put_Line ("=== Task Priority Demo (FIFO_Within_Priorities) ===");
Put_Line ("Main: waiting for tasks to complete...");
delay until Clock + Milliseconds (800);
Put_Line ("Main: done");
end Task_Priority_Demo;
পয়েন্ট:
pragma Priorityদিয়ে প্রতিটি টাস্কে static priority দেওয়া হয়।Priority'Lastসর্বোচ্চ,Priority'Firstসর্বনিম্ন।- এই ডেমোর টাস্ক বডি ভারী computation নয়;
delay untilদিয়ে নির্দিষ্ট সময় পর্যন্ত অপেক্ষা করে। এখানে দেখতে চাই, একসঙ্গে runnable হলে উচ্চ priority টাস্ক আগে execution সুযোগ পায়। - এই চিত্র
FIFO_Within_Priorities-এর মধ্যে ভিন্ন priority-র মধ্যকার preemption দিকটা দেখায়। একই priority-র ভিতরে FIFO ক্রম দেখতে হলে একই priority-র একাধিক টাস্ক সাজানো আলাদা উদাহরণ লাগে। - বাস্তব সিস্টেমে সাধারণত
System.Default_Priorityধরে relative priority ডিজাইন করা হয়।
sequenceDiagram
accTitle: FIFO_Within_Priorities-এ উচ্চ priority টাস্কের preemption
accDescr: একসঙ্গে runnable হলে scheduler প্রথমে উচ্চ priority টাস্ক চালায়, delay until-এর পর নির্ধারিত সময়ে সেগুলো আবার জেগে ওঠে।
participant S as Scheduler
participant Main as Main টাস্ক
participant HP as উচ্চ priority টাস্ক<br/>(Priority=Last)
participant LP as নিম্ন priority টাস্ক<br/>(Priority=First)
Main->>HP: টাস্ক তৈরি
Main->>LP: টাস্ক তৈরি
Note over HP,LP: T=0ms: দুই টাস্কই runnable
S->>HP: সর্বোচ্চ priority-র HP বেছে নেয়
activate HP
Note over HP: শুরুর লগ লেখে
HP->>S: delay until T+100ms-এ block
deactivate HP
S->>LP: তারপর LP চালায়
activate LP
Note over LP: শুরুর লগ লেখে
LP->>S: delay until T+500ms-এ block
deactivate LP
Note over S: T=100ms: HP জেগে ওঠে
S->>HP: HP চালায়
activate HP
Note over HP: শেষের লগ লেখে
deactivate HP
Note over S: T=500ms: LP জেগে ওঠে
S->>LP: LP চালায়
activate LP
Note over LP: শেষের লগ লেখে
deactivate LP
Note over Main: (T=800ms) Main শেষ
রান উদাহরণ (GNAT 13.3.0 / Ubuntu 24.04, x86-64):
$ gnatchop -w 01_task_priority.ada . # → task_priority_demo.adb
$ gnatmake task_priority_demo.adb
$ ./task_priority_demo
[T=0.0s] High priority task started
[T=0.0s] Low priority task started
=== Task Priority Demo (FIFO_Within_Priorities) ===
Main: waiting for tasks to complete...
[T=0.1s] High priority task completed
[T=0.5s] Low priority task completed
Main: done
দুই টাস্কের শুরুর লগ মেইনের শিরোনাম সারির আগে বেরিয়েছে—এদিকে খেয়াল রাখুন। ডিক্লারেশন অংশের টাস্ক ঘিরে থাকা সাবপ্রোগ্রামের বডিতে ঢোকার আগেই activate হয়, তাই এমন ক্রম হতে পারে। আরও, শুরুর এই দুই লাইনের ক্রম রানভেদে উল্টে যেতে পারে। অধ্যায় 12-এ বলা হয়েছে, pragma Priority বাস্তব scheduling-এ কীভাবে পড়ে তা OS ও GNAT runtime-এর উপর; general-purpose Linux-এ priority অনুযায়ী স্টার্ট অর্ডার গ্যারান্টি নেই। এই উদাহরণে স্থিরভাবে দেখা যায় delay until-এ লেখা 0.1 সেকেন্ড / 0.5 সেকেন্ডের শেষ হওয়ার ক্রম।
Ada-এর priority সীমা (GNAT-এর ডিফল্ট):
Priority'First = 0 (সর্বনিম্ন)
Priority'Last = 30 (সর্বোচ্চ, তবে OS-এর উপর নির্ভর করে)
4. Ceiling_Locking ── ভাষাই priority inversion ঠেকায়
রিয়েল-টাইম সিস্টেমের সবচেয়ে জটিল সমস্যাগুলোর একটি priority inversion। উচ্চ priority টাস্ক নিম্ন priority টাস্কের ধরে রাখা lock-এর অপেক্ষা করে, আর সেই নিম্ন priority টাস্ককে মধ্যম priority টাস্ক preempt করলে উচ্চ priority টাস্ক অনির্দিষ্টকাল block হয়ে যায়।
Ada এই সমস্যায় Ceiling_Locking protocol সরাসরি protected object-এ বসিয়ে দিয়েছে।
-- 02_ceiling_locking.ada
-- Ceiling_Locking protocol দিয়ে priority inversion প্রতিরোধ
-- configuration pragma context clause-এর আগে রাখতে হয়
pragma Locking_Policy (Ceiling_Locking);
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
procedure Ceiling_Locking_Demo is
Ceiling : constant System.Any_Priority := System.Any_Priority'Last;
protected Shared_Data is
pragma Priority (Ceiling);
procedure Write (V : Integer);
function Read return Integer;
private
Value : Integer := 0;
end Shared_Data;
protected body Shared_Data is
procedure Write (V : Integer) is
begin
Value := V;
end Write;
function Read return Integer is
begin
return Value;
end Read;
end Shared_Data;
task Producer is
pragma Priority (Priority'Last);
pragma Storage_Size (4 * 1024);
end Producer;
task Consumer is
pragma Priority (Priority'First);
pragma Storage_Size (4 * 1024);
end Consumer;
task body Producer is
begin
Put_Line ("[T=0.0s] Producer (high prio): about to write");
Shared_Data.Write (42);
Put_Line ("[T=0.0s] Producer (high prio): write done");
delay until Clock + Milliseconds (100);
end Producer;
task body Consumer is
begin
delay until Clock + Milliseconds (10);
Put_Line ("[T=0.01s] Consumer (low prio): about to read");
declare
V : Integer;
begin
V := Shared_Data.Read;
Put_Line ("[T=0.01s] Consumer (low prio): read done, got" &
Integer'Image (V));
end;
delay until Clock + Milliseconds (100);
end Consumer;
begin
Put_Line ("=== Ceiling_Locking Demo ===");
Put_Line ("Main: producer priority = Last, consumer priority = First");
Put_Line ("Ceiling = Any_Priority'Last, locking = Ceiling_Locking");
delay until Clock + Milliseconds (300);
Put_Line ("Main: done");
end Ceiling_Locking_Demo;
Ceiling_Locking কীভাবে কাজ করে:
- Protected object-এ
pragma Priority (Ceiling)দিয়ে ceiling priority সেট করা। - যে টাস্কই protected object-এ ঢুকুক, ঢোকার সময় স্বয়ংক্রিয়ভাবে ceiling priority-তে উঠে যায়।
- ফলে protected object ব্যবহাররত টাস্ককে মধ্যম priority-র টাস্ক preempt করতে পারে না।
- Protected object থেকে বেরোলে আগের priority-তে ফেরে।
নিচের চিত্র আগের স্যাম্পল কোডের হুবহু সময় ট্রেস নয়; চিত্র 2-এর priority inversion প্যাটার্ন Ceiling_Locking-এ কীভাবে ঠেকানো হয়, সেই ধারণাচিত্র।
sequenceDiagram
accTitle: Ceiling_Locking কীভাবে priority inversion ঠেকায়
accDescr: Protected object-এ ঢোকার সময় টাস্ক ceiling priority-তে উঠে যায়, তাই মধ্যম priority টাস্ক তাকে preempt করতে পারে না।
participant S as Scheduler
participant L as নিম্ন priority টাস্ক<br/>(priority=10)
participant M as মধ্যম priority টাস্ক<br/>(priority=20)
participant H as উচ্চ priority টাস্ক<br/>(priority=30)
participant PO as Protected object<br/>(ceiling priority=30)
Note over PO: Active priority > ceiling priority এমন caller-এ Program_Error<br/>চিত্রের H(30) ceiling(30)-এর সমান, তাই ঢুকতে পারে
L->>PO: Protected operation-এ ঢোকে
activate L
Note over L,PO: Execution priority 30-এ উঠে যায়
Note over S: M জেগে ওঠে
Note over S,L: L ceiling priority 30-এ চলছে<br/>M(20) preempt করতে পারে না
Note over S: H জেগে ওঠে
Note over S,H: H(30) ceiling চেক পাস করে<br/>তবে L PO ব্যবহার করছে, তাই অপেক্ষা করে
L->>PO: Operation চালায়
L->>PO: Protected operation থেকে বেরোয়
deactivate L
Note over L: Priority 10-এ ফেরে
Note over S,H: PO ছাড়ার পর H চালায়
activate H
H->>PO: Protected operation-এ ঢোকে
Note over H,PO: H(30) = ceiling(30), তাই contention মিটলে ঢুকতে পারে
H->>PO: Protected operation থেকে বেরোয়
deactivate H
ডিজাইন নির্দেশ: Protected object-এর ceiling priority সেই object ব্যবহার করা সব টাস্কের সর্বোচ্চ priority-র সমান বা তার বেশি হতে হবে। এটা ভেঙে ceiling-এর চেয়ে উচ্চ active priority-র টাস্ক protected operation ডাকলে Ada
Program_Errorদিয়ে ডিজাইন ভুল ধরতে পারে।
C-এর pthread mutex দিয়ে একই কাজ করতে PTHREAD_PRIO_PROTECT অ্যাট্রিবিউট স্পষ্ট করে সেট করতে হয়; Ada-তে এটা ভাষার মানক ফিচার।
5. delay until ── periodic টাস্ক drift ছাড়া চালানো
রিয়েল-টাইম সিস্টেমের মৌলিক প্যাটার্ন periodic টাস্ক। নির্দিষ্ট ব্যবধানে বারবার চলা টাস্কে cumulative timing error (drift) ঠেকানো অত্যন্ত জরুরি।
Ada-এর delay until এই সমস্যা পরিষ্কারভাবে সমাধান করে।
-- 03_periodic_task.ada
-- delay until দিয়ে periodic টাস্ক ── cumulative drift ঠেকানো
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
procedure Periodic_Task_Demo is
Period_MS : constant Time_Span := Milliseconds (200);
Cycles : constant Positive := 5;
task Sensor_Reader is
pragma Priority (Priority'Last - 2);
pragma Storage_Size (4 * 1024);
end Sensor_Reader;
task body Sensor_Reader is
Start_Time : constant Time := Clock;
Next_Release : Time := Start_Time + Period_MS;
Cycle_Count : Natural := 0;
begin
Put_Line ("[Sensor] Periodic task starts, period=" &
To_Duration (Period_MS)'Image & "s, cycles=" &
Natural'Image (Cycles));
for I in 1 .. Cycles loop
delay until Next_Release;
Cycle_Count := Cycle_Count + 1;
Put_Line ("[Sensor] Cycle" & Natural'Image (Cycle_Count) &
" at" & Duration'Image (To_Duration (Clock - Start_Time)) & "s");
Next_Release := Next_Release + Period_MS;
end loop;
Put_Line ("[Sensor] Periodic task finished. Actual elapsed:" &
Duration'Image (To_Duration (Clock - Start_Time)) & "s");
end Sensor_Reader;
begin
Put_Line ("=== Periodic Task Demo (delay until) ===");
Put_Line ("Main: waiting for" & Natural'Image (Cycles) & " cycles...");
delay until Clock + Milliseconds (1500);
Put_Line ("Main: done");
end Periodic_Task_Demo;
কেন delay until:
| পদ্ধতি | সমস্যা |
|---|---|
delay Period; |
প্রতি iteration-এর processing time যোগ হয়ে period ধীরে ধীরে সরে যায় (cumulative drift) |
delay until Next_Release; Next_Release := Next_Release + Period; |
absolute time ধরে চলে, তাই একবারের কাজ দেরি হলেও পরের release time ঠিক থাকে |
তবে delay until processing time যেন period-এর ভিতরে থাকে, সেটা নিজে থেকে গ্যারান্টি দেয় না। কাজ যদি পরের wake time ছাড়িয়ে যায়, সেই delay until প্রায় সঙ্গে সঙ্গে ফিরে আসে, আর সিস্টেমকে deadline miss হিসেবে ধরতে হয়।
delay-এর ক্ষেত্রে:
T=0ms → কাজ(15ms) → delay 100ms → T=115ms → কাজ(10ms) → ...
আসল ব্যবধান: 115ms, 110ms, ... (processing time জমা হয়)
delay until-এর ক্ষেত্রে:
Next_Release: 100ms, 200ms, 300ms, ... (absolute time)
T=0ms → কাজ(15ms) → delay until 100ms → T=100ms → কাজ(10ms) → delay until 200ms
আসল ব্যবধান: 100ms, 100ms, ... (processing time-এর উপর নির্ভর করে না)
রান উদাহরণ (GNAT 13.3.0 / Ubuntu 24.04, x86-64):
$ gnatchop -w 03_periodic_task.ada . # → periodic_task_demo.adb
$ gnatmake periodic_task_demo.adb
$ ./periodic_task_demo
[Sensor] Periodic task starts, period= 0.200000000s, cycles= 5
=== Periodic Task Demo (delay until) ===
Main: waiting for 5 cycles...
[Sensor] Cycle 1 at 0.200326876s
[Sensor] Cycle 2 at 0.400159550s
[Sensor] Cycle 3 at 0.600183089s
[Sensor] Cycle 4 at 0.800327451s
[Sensor] Cycle 5 at 1.000260472s
[Sensor] Periodic task finished. Actual elapsed: 1.000297359s
Main: done
প্রতি সাইকেলে প্রায় 0.2–0.3 মিলিসেকেন্ড wake delay দেখা যায়, কিন্তু সেই delay পরের period-এ গড়িয়ে যায়নি। 5 নম্বর সাইকেলেও বেস সময় থেকে সরে যাওয়া 1 মিলিসেকেন্ডের কম। delay Period; দিয়ে লিখলে এই delay প্রতিবার জমে 5 সাইকেল পরে চোখে পড়ত। এই সংখ্যা general-purpose Linux-এর একটি উদাহরণ; hard real-time পরিবেশে গ্যারান্টি করা মান নয়।
এই delay until প্যাটার্ন এখান থেকে সব periodic টাস্কে ব্যবহার করব।
flowchart TB
accTitle: delay Period বনাম delay until
accDescr: Relative delay cumulative drift তৈরি করে; delay until absolute time ধরে চলে, কিন্তু period ছাড়িয়ে গেলে deadline miss ধরতে হয়।
subgraph Bad["delay Period - cumulative drift"]
B1[T=0ms: processing 15ms] --> B2[delay 100ms → 115ms-এ জাগে]
B2 --> B3[processing 10ms → 125ms]
B3 --> B4[delay 100ms → 225ms-এ জাগে]
B4 --> B5[আসল ব্যবধান: 115ms, 110ms...]
end
subgraph Good["delay until - absolute time-এর ভিত্তি"]
G1[পরেরবার = T+100ms] --> G2[processing 15ms]
G2 --> G3[delay until T+100ms → 100ms-এ জাগে]
G3 --> G4[processing 10ms]
G4 --> G5[পরেরবার = T+200ms → 200ms-এ জাগে]
G5 --> G6[আসল ব্যবধান: 100ms, 100ms...]
end
subgraph Overrun["Period ছাড়িয়ে যাওয়া - deadline miss"]
O1[পরেরবার = T+100ms] --> O2[processing 130ms]
O2 --> O3[delay until T+100ms সঙ্গে সঙ্গে ফেরে]
O3 --> O4[দেরি ধরে overload হিসেবে সামলানো]
end
Bad --> Drift[সময়ের সঙ্গে ত্রুটি জমা হয়]
Good --> Stable[Cumulative drift ঠেকায়]
Good --> Overrun
6. Ravenscar profile ── যাচাইযোগ্য রিয়েল-টাইম subset
Ada-এর টাস্ক ফিচার শক্তিশালী, কিন্তু নিরাপত্তা অত্যন্ত গুরুত্বপূর্ণ সিস্টেমে “অতিরিক্ত শক্তিশালী” হয়ে সমস্যা হয়। Dynamic টাস্ক তৈরি, select statement, abort statement ইত্যাদি worst-case execution time-এর static analysis কঠিন করে তোলে।
Ravenscar profile এই সমস্যার Ada-এর জবাব। টাস্ক ফিচারকে statically analyzable ও deterministic subset-এ সীমিত করে।
-- 04_ravenscar_profile.ada
-- Ravenscar profile-এর মৌলিক রূপ
-- কম্পাইলের সময় gnat.adc-এ pragma Profile (Ravenscar); নির্দিষ্ট করতে হয়
-- বিল্ড: gnatchop -w 04_ravenscar_profile.ada .
-- → ravenscar_state.ads / ravenscar_state.adb / ravenscar_demo.adb-এ ভাগ হয়
-- gnat.adc তৈরি করে তারপর gnatmake ravenscar_demo.adb
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
package Ravenscar_State is
protected Signal is
pragma Priority (System.Default_Priority + 5);
entry Wait_For_Release;
procedure Release;
private
Released : Boolean := False;
end Signal;
task Periodic_Worker is
pragma Priority (System.Default_Priority + 1);
pragma Storage_Size (4 * 1024);
end Periodic_Worker;
task Monitor is
pragma Priority (System.Default_Priority);
pragma Storage_Size (4 * 1024);
end Monitor;
end Ravenscar_State;
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
package body Ravenscar_State is
protected body Signal is
entry Wait_For_Release when Released is
begin
Released := False;
end Wait_For_Release;
procedure Release is
begin
Released := True;
end Release;
end Signal;
task body Periodic_Worker is
Start_Time : constant Time := Clock;
Next_Release : Time := Start_Time + Milliseconds (100);
Period : constant Time_Span := Milliseconds (100);
Cycle_Count : Natural := 0;
begin
Put_Line ("[Worker] Ravenscar periodic task starts");
for I in 1 .. 4 loop
delay until Next_Release;
Cycle_Count := Cycle_Count + 1;
Put_Line ("[Worker] Cycle" & Natural'Image (Cycle_Count) &
" at" & Duration'Image (To_Duration (Clock - Start_Time)) & "s");
Signal.Release;
Next_Release := Next_Release + Period;
end loop;
Put_Line ("[Worker] Finished demo, waiting (Ravenscar: No_Task_Termination)");
loop
delay until Clock + Seconds (1);
end loop;
end Periodic_Worker;
task body Monitor is
begin
Put_Line ("[Monitor] Waiting for signals...");
for I in 1 .. 4 loop
Signal.Wait_For_Release;
Put_Line ("[Monitor] Received signal" & Natural'Image (I));
end loop;
Put_Line ("[Monitor] All signals received, waiting (Ravenscar: No_Task_Termination)");
loop
delay until Clock + Seconds (1);
end loop;
end Monitor;
end Ravenscar_State;
with Ravenscar_State; use Ravenscar_State;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure Ravenscar_Demo is
begin
Put_Line ("=== Ravenscar Profile Demo ===");
Put_Line ("(compile with: gnatmake -gnatec=gnat.adc ravenscar_demo)");
Put_Line ("Main: waiting for Ravenscar tasks...");
delay until Clock + Milliseconds (800);
Put_Line ("Main: demo window elapsed; waiting forever (Ravenscar: No_Task_Termination)");
loop
delay until Clock + Seconds (1);
end loop;
end Ravenscar_Demo;
Ravenscar profile-এর সীমাবদ্ধতা:
| নিষিদ্ধ ফিচার | কারণ |
|---|---|
Dynamic টাস্ক তৈরি (new বা access type) |
রানটাইম মেমরি বরাদ্দ non-deterministic |
select statement |
শুধু একাধিক বিকল্প নয়, select statement পুরোটাই control-flow analysis কঠিন করে |
abort statement |
Asynchronous abort অবস্থাকে অনির্দেশ্য করে |
Ada.Task_Attributes |
রানটাইম dynamic আচরণ |
| Dynamic priority পরিবর্তন | Scheduling analysis-এর অনুমান রানটাইমে বদলে যায় |
Relative delay (delay) |
Cumulative drift তৈরি করে সহজে, তাই absolute time-এর delay until ব্যবহার করতে হয় |
| প্রতি protected object-এ একাধিক entry | Blocking শর্ত ও বিশ্লেষণের বিষয় বেড়ে যায় |
| টাস্ক শেষ হওয়া | Ravenscar-এ সব টাস্ককে non-terminating ধরা হয় |
requeue statement |
Control-flow ট্র্যাক করা জটিল হয় |
এই সীমাবদ্ধতায় Ravenscar-অনুসারী প্রোগ্রাম static timing analysis করা সহজ রূপ পায়। এটা DO-178C (বিমান সফটওয়্যার) বা ISO 26262 (স্বয়ংচালিত functional safety)-এর মতো নিরাপত্তা মানে চাওয়া বৈশিষ্ট্য। নিচের তালিকা প্রধান সীমাবদ্ধতার নির্বাচিত অংশ; আসল profile-এ No_Task_Hierarchy বা Detect_Blocking-এর মতো runtime ও বিশ্লেষণযোগ্যতা নিয়ে অতিরিক্ত নিয়মও থাকে।
flowchart TB
accTitle: Ravenscar profile-এর সীমাবদ্ধতা ও নীতি
accDescr: Ada টাস্কিংকে static analysis-যোগ্য subset-এ সীমিত করে FIFO_Within_Priorities ও Ceiling_Locking বাধ্যতামূলক করে, যা নিরাপত্তা মান পূরণে সহায়ক।
Full[পূর্ণ Ada টাস্ক ফিচার] --> Profile[Ravenscar profile]
Profile --> Restrict[সীমাবদ্ধতা]
Profile --> Policy[বাধ্যতামূলক policy]
Restrict --> R1[Dynamic টাস্ক তৈরি নিষিদ্ধ]
Restrict --> R2[select statement নিষিদ্ধ]
Restrict --> R3[abort statement নিষিদ্ধ]
Restrict --> R4[Task_Attributes নিষিদ্ধ]
Restrict --> R5[প্রতি protected object-এ 1 entry-তে সীমা]
Restrict --> R6[requeue statement নিষিদ্ধ]
Restrict --> R7[Relative delay নিষিদ্ধ<br/>delay until ব্যবহার]
Restrict --> R8[Dynamic priority পরিবর্তন নিষিদ্ধ]
Restrict --> R9[টাস্ক শেষ হওয়া নিষিদ্ধ<br/>সব টাস্ক non-terminating]
Policy --> P1[FIFO_Within_Priorities]
Policy --> P2[Ceiling_Locking]
Restrict --> Benefit[যা সহজ হয়:<br/>static timing analysis]
Policy --> Benefit
Benefit --> DO178[DO-178C<br/>বিমান সফটওয়্যার]
Benefit --> ISO26262[ISO 26262<br/>স্বয়ংচালিত functional safety]
Benefit --> IEC62304[IEC 62304<br/>চিকিৎসা যন্ত্রের সফটওয়্যার]
Ravenscar profile চালু করতে gnat.adc ফাইলে নিচের লাইন লিখতে হয়:
pragma Profile (Ravenscar);
7. Timing event ── polling ছাড়া সময়চালিত জাগানো
অনেক রিয়েল-টাইম সিস্টেমে “নির্দিষ্ট সময়ে উচ্চ priority টাস্ক জাগাতে হবে” এমন চাহিদা বারবার আসে। সরল বাস্তবায়নে টাইমার poll করতে হয়, কিন্তু Ada আরও পরিশীলিত ব্যবস্থা দেয়—timing event।
-- 05_timing_events.ada
-- Timing event (Ada.Real_Time.Timing_Events)
-- উচ্চ priority টাস্ককে polling ছাড়া জাগানোর ব্যবস্থা
-- বিল্ড: gnatchop -w 05_timing_events.ada .
-- → signal_pkg.ads / signal_pkg.adb / timing_events_demo.adb-এ ভাগ হয়
-- gnatmake timing_events_demo.adb
pragma Locking_Policy (Ceiling_Locking);
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;
package Signal_Pkg is
protected type Signal_Type is
pragma Priority (System.Interrupt_Priority'Last);
entry Wait_For_Event;
procedure Fire (Event : in out Timing_Event);
private
Fired : Boolean := False;
end Signal_Type;
S : Signal_Type;
end Signal_Pkg;
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;
package body Signal_Pkg is
protected body Signal_Type is
entry Wait_For_Event when Fired is
begin
Fired := False;
end Wait_For_Event;
procedure Fire (Event : in out Timing_Event) is
begin
Fired := True;
end Fire;
end Signal_Type;
end Signal_Pkg;
with Signal_Pkg; use Signal_Pkg;
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Real_Time.Timing_Events; use Ada.Real_Time.Timing_Events;
procedure Timing_Events_Demo is
pragma Priority (29);
Timer_1 : Timing_Event;
Timer_2 : Timing_Event;
task Reactor is
pragma Priority (System.Default_Priority + 5);
pragma Storage_Size (4 * 1024);
end Reactor;
task body Reactor is
begin
Put_Line ("[Reactor] Waiting for timing events...");
S.Wait_For_Event;
Put_Line ("[Reactor] Got event #1");
S.Wait_For_Event;
Put_Line ("[Reactor] Got event #2");
Put_Line ("[Reactor] Done");
end Reactor;
begin
Put_Line ("=== Timing Events Demo ===");
Put_Line ("Scheduling two timers at +100ms and +250ms...");
Set_Handler (Timer_1, Clock + Milliseconds (100), S.Fire'Access);
Set_Handler (Timer_2, Clock + Milliseconds (250), S.Fire'Access);
delay until Clock + Milliseconds (500);
Put_Line ("Main: done");
end Timing_Events_Demo;
Timing event কীভাবে চলে:
1. Set_Handler(Timer_1, T+100ms, S.Fire'Access) ── absolute time-এ handler register করা
2. T+100ms পার ── runtime S.Fire-কে **ceiling priority-তে** ডাকে
3. Fire Fired ফ্ল্যাগ True করে ── barrier খুলে যায়
4. Reactor টাস্ক Wait_For_Event থেকে জেগে ওঠে
গুরুত্বপূর্ণ বিষয়, এই উদাহরণে Ceiling_Locking স্পষ্ট করা আছে, আর Fire handler protected object-এর procedure বলে ceiling priority-তে চলে। Timing event-এর handler হিসেবে ব্যবহার করা protected procedure এমন protected object-এ রাখতে হয় যার ceiling priority interrupt-স্তরের—এখানে System.Interrupt_Priority'Last। এতে timing event সামলানোর সময় priority inversion হয় না।
8. Protected object দিয়ে রিয়েল-টাইম কিউ
রিয়েল-টাইম সিস্টেমে ঘন ঘন দেখা প্যাটার্ন producer–consumer। সেন্সর ডেটা তৈরি করে, কন্ট্রোল টাস্ক সেটা consume করে—এখানে বাফারের mutual exclusion ও blocking দক্ষভাবে সামলাতে হয়।
Ada-এর protected object ও entry barrier দিয়ে এটা barrier-ভিত্তিক সিঙ্ক হিসেবে লেখা যায়। ভিতরে runtime mutual exclusion সামলায়, তাই অ্যাপ্লিকেশন কোডে mutex বা condition variable সরাসরি লিখতে হয় না।
-- 06_protected_queue.ada
-- Protected object দিয়ে রিয়েল-টাইম ডেটা শেয়ারিং
-- পাইপলাইন: Producer -> Bounded_Buffer -> Consumer
-- কম্পাইলের সময় gnat.adc-এ pragma Locking_Policy (Ceiling_Locking); নির্দিষ্ট করতে হয়
pragma Locking_Policy (Ceiling_Locking);
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
procedure Protected_Queue_Demo is
Buffer_Size : constant := 4;
type Buf_Array is array (1 .. Buffer_Size) of Integer;
protected Bounded_Buffer is
pragma Priority (System.Any_Priority'Last);
entry Put (Item : Integer);
entry Get (Item : out Integer);
private
Buf : Buf_Array;
Count : Natural := 0;
Head : Positive := 1;
Tail : Positive := 1;
end Bounded_Buffer;
protected body Bounded_Buffer is
entry Put (Item : Integer) when Count < Buffer_Size is
begin
Buf (Tail) := Item;
Tail := (Tail mod Buffer_Size) + 1;
Count := Count + 1;
end Put;
entry Get (Item : out Integer) when Count > 0 is
begin
Item := Buf (Head);
Head := (Head mod Buffer_Size) + 1;
Count := Count - 1;
end Get;
end Bounded_Buffer;
task Producer is
pragma Priority (System.Default_Priority + 2);
pragma Storage_Size (4 * 1024);
end Producer;
task Consumer is
pragma Priority (System.Default_Priority + 1);
pragma Storage_Size (4 * 1024);
end Consumer;
task body Producer is
Next_Release : Time := Clock + Milliseconds (50);
Period : constant Time_Span := Milliseconds (50);
begin
for I in 1 .. 6 loop
Bounded_Buffer.Put (I);
Put_Line ("[Producer] Put" & Integer'Image (I));
delay until Next_Release;
Next_Release := Next_Release + Period;
end loop;
Put_Line ("[Producer] Done");
end Producer;
task body Consumer is
Item : Integer;
Next_Release : Time := Clock + Milliseconds (80);
Period : constant Time_Span := Milliseconds (80);
begin
delay until Clock + Milliseconds (30);
for I in 1 .. 6 loop
Bounded_Buffer.Get (Item);
Put_Line ("[Consumer] Got" & Integer'Image (Item));
delay until Next_Release;
Next_Release := Next_Release + Period;
end loop;
Put_Line ("[Consumer] Done");
end Consumer;
begin
Put_Line ("=== Protected Queue Demo (Ceiling_Locking) ===");
Put_Line ("Buffer size = 4; Producer every 50ms, Consumer every 80ms");
delay until Clock + Milliseconds (800);
Put_Line ("Main: done");
end Protected_Queue_Demo;
ডিজাইনের মূল কথা:
entry Put when Count < Buffer_Size── বাফার ভর্তি থাকলে Producer স্বয়ংক্রিয়ভাবে block হয়।entry Get when Count > 0── বাফার খালি থাকলে Consumer স্বয়ংক্রিয়ভাবে block হয়।pragma Priority (System.Any_Priority'Last)── ceiling locking-এর ফলে Producer ও Consumer-এর মধ্যে priority inversion হয় না।- Barrier শর্ত protected object-এর অভ্যন্তরীণ অবস্থা (
Count) দিয়ে লেখা, আর lock ছাড়ার সময় স্বয়ংক্রিয়ভাবে আবার মূল্যায়ন হয়।
এই কোডে অ্যাপ্লিকেশন-স্তরের mutex, semaphore বা condition variable নেই। দরকারি অপেক্ষা protected object-এর entry barrier দিয়েই প্রকাশ করা।
stateDiagram-v2
accTitle: Bounded buffer-এর empty, partial, full অবস্থা
accDescr: Put ও Get barrier Count অনুযায়ী টাস্ককে block করে বা এগোতে দেয়।
Empty: খালি / Count=0
Partial: কিছু আছে / Count=1..Buffer_Size-1
Full: ভর্তি / Count=Buffer_Size
[*] --> Empty: প্রাথমিক অবস্থা
Empty --> Partial: Put (1 উপাদান যোগ)
Partial --> Partial: Put / Get
Partial --> Empty: Get (শেষ উপাদান নেওয়া)
Partial --> Full: Put (শেষ খালি ঘর ভরা)
Full --> Partial: Get (একটি খালি হয়)
Empty --> Empty: Get block হয় (barrier Count=0)
Full --> Full: Put block হয় (barrier Count=Buffer_Size)
Put সফল হলে Get-এর অপেক্ষা, Get সফল হলে Put-এর অপেক্ষা আবার মূল্যায়ন হয়। চিত্রে যে অবস্থায়ই থাকুক, protected operation শেষ হওয়ার সময় এটা হয়।
9. Execution time পরিমাপ ── monitoring-এর প্রথম ধাপ
রিয়েল-টাইম সিস্টেমের schedulability মূল্যায়ন করতে প্রতিটি টাস্কের execution time (CPU time) সঠিকভাবে জানা দরকার। Ada-এর Ada.Execution_Time প্যাকেজ টাস্কপ্রতি CPU খরচ দেয়।
-- 07_execution_time.ada
-- Execution time পরিমাপ (Execution_Time)
-- টাস্কপ্রতি CPU খরচ পরিমাপ
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Execution_Time;
use type Ada.Execution_Time.CPU_Time;
procedure Execution_Time_Demo is
package ET renames Ada.Execution_Time;
task Busy_Worker is
pragma Priority (System.Default_Priority + 1);
pragma Storage_Size (4 * 1024);
end Busy_Worker;
task body Busy_Worker is
Wall_Start : Time;
Cpu_Start : ET.CPU_Time;
Dummy : Integer := 0;
pragma Volatile (Dummy);
begin
Wall_Start := Clock;
Cpu_Start := ET.Clock;
Put_Line ("[Worker] Starting compute-bound work...");
for I in 1 .. 20_000_000 loop
Dummy := Dummy + 1;
end loop;
Put_Line ("[Worker] Dummy =" & Integer'Image (Dummy));
declare
Wall_Elapsed : constant Duration :=
To_Duration (Clock - Wall_Start);
Cpu_Span : constant Time_Span :=
ET.Clock - Cpu_Start;
begin
Put_Line ("[Worker] Done, wall time:" &
Duration'Image (Wall_Elapsed) & "s");
Put_Line ("[Worker] CPU time consumed:" &
Duration'Image (To_Duration (Cpu_Span)) & "s");
end;
end Busy_Worker;
Cpu_Start_Main : constant ET.CPU_Time := ET.Clock;
begin
Put_Line ("=== Execution Time Demo ===");
delay until Clock + Milliseconds (500);
declare
Cpu_Span : constant Time_Span := ET.Clock - Cpu_Start_Main;
begin
Put_Line ("Main: CPU time consumed after 500ms:" &
Duration'Image (To_Duration (Cpu_Span)) & "s");
end;
Put_Line ("Main: done");
end Execution_Time_Demo;
Wall-clock time বনাম CPU time:
Wall-clock time: Ada.Real_Time.Clock
→ আসল অতিবাহিত সময়। Block বা preempt হওয়া সময়ও ধরে।
CPU time (execution time): Ada.Execution_Time.Clock
→ সেই টাস্ক CPU-তে সত্যি চলার সময়ই।
→ Block বা preempt হওয়া সময় গোনা হয় না।
এই পার্থক্য execution time monitoring ও WCET যাচাইয়ের সূচনা। Busy_Worker delay until-এ অপেক্ষা করলে CPU time বাড়ে না; আসল processing চলার সময়ই বাড়ে। Main টাস্কের delay until Clock + Milliseconds(500)-এর মধ্যেও CPU time প্রায় শূন্য হওয়া উচিত। তবে CPU time-এর মাপ সত্যিকারের WCET গ্যারান্টি করে না। Cache, pipeline, মেমরি contention সহ WCET-এর জন্য আলাদা করে static analysis বা টার্গেট পরিবেশে যাচাই লাগে।
flowchart LR
accTitle: Wall-clock time বনাম CPU time
accDescr: Wall clock অপেক্ষা ও preemption ধরে; CPU time শুধু আসল processing ধরে, তাই WCET যাচাইয়ের সহায়ক কিন্তু নিশ্চয়তা নয়।
subgraph Wall[Wall-clock time]
W1[মোট অতিবাহিত সময়: 500ms] --> W2[breakdown: processing + wait + block + preempt]
end
subgraph CPU[CPU time]
C1[মোট CPU time: 120ms] --> C2[breakdown: শুধু আসল processing]
end
Wall --> Diff[ফারাক = অপেক্ষা, block, preempt সময়]
CPU --> Diff
Diff --> Insight[CPU time আসল processing খরচ দেখে<br/>WCET যাচাই ও monitoring-এর সহায়ক<br/>অপেক্ষা, block, preempt সময় বাদ দেয়]
Insight --> Caveat[সতর্কতা<br/>মাপ সত্যিকারের WCET গ্যারান্টি করে না<br/>Static analysis বা টার্গেট যাচাই দরকার]
10. সমন্বিত ডেমো ── মাল্টি-পিরিয়ডিক রিয়েল-টাইম সিস্টেম
এখান পর্যন্ত শেখা সব উপাদান—priority, Ceiling_Locking, delay until, protected object—একত্র করে একটি সাধারণ মাল্টি-পিরিয়ডিক রিয়েল-টাইম সিস্টেম গড়ব।
-- 08_multiperiodic.ada
-- মাল্টি-পিরিয়ডিক রিয়েল-টাইম সিস্টেমের সমন্বিত ডেমো
-- দ্রুত period (100ms)-এর সেন্সর পড়ার টাস্ক
-- ধীর period (400ms)-এর কন্ট্রোল টাস্ক
-- Ceiling_Locking দিয়ে ডেটা শেয়ারিং
pragma Locking_Policy (Ceiling_Locking);
with Ada.Text_IO; use Ada.Text_IO;
with System; use System;
with Ada.Real_Time; use Ada.Real_Time;
procedure Multiperiodic_Demo is
package Int_IO is new Ada.Text_IO.Integer_IO (Integer);
protected Shared_Sensor is
pragma Priority (System.Any_Priority'Last);
procedure Write (V : Integer);
function Read return Integer;
private
Value : Integer := 0;
end Shared_Sensor;
protected body Shared_Sensor is
procedure Write (V : Integer) is
begin
Value := V;
end Write;
function Read return Integer is
begin
return Value;
end Read;
end Shared_Sensor;
task Fast_Sensor is
pragma Priority (System.Default_Priority + 3);
pragma Storage_Size (4 * 1024);
end Fast_Sensor;
task body Fast_Sensor is
Next_Release : Time := Clock + Milliseconds (100);
Period : constant Time_Span := Milliseconds (100);
Cycle : Natural := 0;
begin
Put_Line ("[Fast] Sensor reader starts (100ms period)");
for I in 1 .. 12 loop
delay until Next_Release;
Cycle := Cycle + 1;
Shared_Sensor.Write (Cycle * 10);
Next_Release := Next_Release + Period;
end loop;
Put_Line ("[Fast] Done");
end Fast_Sensor;
task Slow_Controller is
pragma Priority (System.Default_Priority + 2);
pragma Storage_Size (4 * 1024);
end Slow_Controller;
task body Slow_Controller is
Next_Release : Time := Clock + Milliseconds (150);
Period : constant Time_Span := Milliseconds (400);
Cycle : Natural := 0;
Raw : Integer;
begin
Put_Line ("[Slow] Controller starts (400ms period)");
for I in 1 .. 3 loop
delay until Next_Release;
Cycle := Cycle + 1;
Raw := Shared_Sensor.Read;
Put_Line ("[Slow] Cycle" & Natural'Image (Cycle) &
" reads sensor =" & Integer'Image (Raw));
Next_Release := Next_Release + Period;
end loop;
Put_Line ("[Slow] Done");
end Slow_Controller;
begin
Put_Line ("=== Multiperiodic Real-Time System Demo ===");
Put_Line ("Fast sensor (100ms) x 12 + Slow controller (400ms) x 3");
Put_Line ("Ceiling_Locking prevents priority inversion on shared data");
delay until Clock + Milliseconds (2000);
Put_Line ("Main: done");
end Multiperiodic_Demo;
সিস্টেম গঠন:
নিচের চিত্র স্যাম্পল কোডের release সময় (দ্রুত সেন্সর 100ms period, ধীর কন্ট্রোল 150ms অফসেটের 400ms period)-এর উপর ব্যাখ্যার জন্য ধরে নেওয়া execution time বসিয়ে একটি schedule উদাহরণ। কোডে নিজে 80ms কন্ট্রোল processing নেই, তাই এটা মাপা চিত্র নয়। দ্রুত সেন্সরের priority বেশি হলে ধীর কন্ট্রোল চলার সময় দ্রুত সেন্সরের release এলে ধীর কন্ট্রোল সাময়িক থেমে যায়। চিত্রে পড়তে সুবিধার জন্য প্রতি ধীর কন্ট্রোল period-এ নমুনা হিসেবে একটি preemption আঁকা; বাস্তবে প্রতি 100ms সীমানায় দ্রুত সেন্সর release হয়।
flowchart TB
accTitle: মাল্টি-পিরিয়ডিক সিস্টেমে fast sensor ও slow controller
accDescr: উচ্চ priority fast sensor slow controller-কে মাঝে মাঝে preempt করে; চিত্রটি ব্যাখ্যার জন্য ধরে নেওয়া execution সময় ব্যবহার করে।
Assumption["ব্যাখ্যার অনুমান<br/>দ্রুত সেন্সর: 10ms কাজ<br/>ধীর কন্ট্রোল: 80ms কাজ"]
subgraph Cycle1["ধীর কন্ট্রোল period 1 (release=150ms)"]
direction LR
C1F1["100-110ms<br/>দ্রুত সেন্সর #1"] --> C1S1["150-200ms<br/>ধীর কন্ট্রোল #1 আগের অংশ"]
C1S1 --> C1F2["200-210ms<br/>দ্রুত সেন্সর #2<br/>P+3 বলে preempt হয়"]
C1F2 --> C1S2["210-240ms<br/>ধীর কন্ট্রোল #1 পরের অংশ"]
end
subgraph Cycle2["ধীর কন্ট্রোল period 2 (release=550ms)"]
direction LR
C2S1["550-600ms<br/>ধীর কন্ট্রোল #2 আগের অংশ"] --> C2F6["600-610ms<br/>দ্রুত সেন্সর #6<br/>P+3 বলে preempt হয়"]
C2F6 --> C2S2["610-640ms<br/>ধীর কন্ট্রোল #2 পরের অংশ"]
end
subgraph Cycle3["ধীর কন্ট্রোল period 3 (release=950ms)"]
direction LR
C3S1["950-1000ms<br/>ধীর কন্ট্রোল #3 আগের অংশ"] --> C3F10["1000-1010ms<br/>দ্রুত সেন্সর #10<br/>P+3 বলে preempt হয়"]
C3F10 --> C3S2["1010-1040ms<br/>ধীর কন্ট্রোল #3 পরের অংশ"]
end
Assumption --> C1F1
C1S2 --> C2S1
C2S2 --> C3S1
এই প্যাটার্ন শিল্প কন্ট্রোল সিস্টেম ও রোবট কন্ট্রোলে ঘন ঘন দেখা “দ্রুত সেন্সর সংগ্রহ + ধীর কন্ট্রোল লুপ”-এর সাধারণ গঠন।
11. Ada-এর রিয়েল-টাইম ফিচার যেখানে সত্যিই কাজে লাগে
Ada-এর রিয়েল-টাইম ফিচার নিচের মতো ক্ষেত্রে বিশেষভাবে মূল্য দেখায়।
flowchart TB
accTitle: Ada Annex D যেসব ক্ষেত্রে কাজে লাগে
accDescr: বিমান ও মহাকাশ, রেল, স্বয়ংচালিত, চিকিৎসা যন্ত্র, শিল্প নিয়ন্ত্রণ ও প্রতিরক্ষায় Ada-এর রিয়েল-টাইম ফিচারের অবস্থান।
Ada[Ada Annex D<br/>রিয়েল-টাইম ফিচার] --> Aero[বিমান ও মহাকাশ<br/>DO-178C]
Ada --> Rail[রেল<br/>EN 50128 series]
Ada --> Auto[স্বয়ংচালিত<br/>ISO 26262]
Ada --> Medical[চিকিৎসা যন্ত্র<br/>IEC 62304]
Ada --> Industrial[শিল্প নিয়ন্ত্রণ<br/>IEC 61508 series]
Ada --> Defense[প্রতিরক্ষা ও উচ্চ-নির্ভরযোগ্য সিস্টেম]
Aero --> A1[ফ্লাইট কন্ট্রোল<br/>প্রমাণিত প্রয়োগক্ষেত্র]
Aero --> A2[স্যাটেলাইট ও মহাকাশযান কন্ট্রোল]
Rail --> R1[সিগন্যালিং সিস্টেম]
Rail --> R2[স্বয়ংক্রিয় ট্রেন কন্ট্রোল]
Auto --> Au1[নিরাপত্তা-সম্পর্কিত ECU-এর candidate]
Auto --> Au2[C / MISRA-C প্রধান ক্ষেত্রে<br/>সীমিত ও বাছাই করা প্রয়োগ]
Medical --> M1[পেসমেকার]
Medical --> M2[ইনফিউশন পাম্প]
Industrial --> I1[রোবট কন্ট্রোল]
Industrial --> I2[NC মেশিন টুল]
Defense --> D1[মিশন কম্পিউটার]
Defense --> D2[দীর্ঘমেয়াদি চালু সিস্টেম]
চিত্রে শুধু স্বয়ংচালিত ক্ষেত্রে “সীমিত ও বাছাই করা প্রয়োগ” লেখা, কারণ ভাষা হিসেবে মানানসই কি না তার চেয়ে বিদ্যমান ইকোসিস্টেমের আকারই বড় কারণ। গাড়ির সফটওয়্যারে AUTOSAR-এর মতো শিল্প মানক API স্পেসিফিকেশন, সাপ্লায়ারের দেওয়া কোড, সার্টিফিকেশন পাস করা কম্পাইলার ও যাচাই টুল, এমনকি ইঞ্জিনিয়ারের সংখ্যা পর্যন্ত C ও MISRA-C ধরে গড়ে উঠেছে। ভাষা বদলানো মানে, লক্ষ্য একটাই কম্পোনেন্ট হলেও তার আশপাশের টুলসেট আর সংগ্রহ–যাচাই প্রক্রিয়া একসঙ্গে নতুন করে সাজানো। তাই Ada গাড়িজুড়ে মানক হওয়ার বদলে, বিশেষ করে উচ্চ নিশ্চয়তা চাওয়া কিছু কম্পোনেন্টে, অথবা যাদের ইতিমধ্যে Ada অ্যাসেট ও ডেভেলপমেন্ট ব্যবস্থা আছে সেই সংস্থায় বাছাই করে ব্যবহৃত হয়—এমন অবস্থানেই পড়ে সহজে। উল্টোদিকে, বিমান–মহাকাশ বা রেলের মতো যেখানে ইকোসিস্টেমই উচ্চ নির্ভরযোগ্যতার দিকে ঝুঁকে আছে, সেখানে এই বাধা শুরুতেই নেই।
12. সতর্কতা ও সীমা
Ada-এর রিয়েল-টাইম ফিচার শক্তিশালী, কিন্তু সব কিছুর সমাধান নয়।
1. প্ল্যাটফর্ম নির্ভরতা:
pragma Priority-এর আসল ম্যাপিং চালানোর পরিবেশের (OS + GNAT runtime) উপর নির্ভর করে। Linux-এ এটাSCHED_FIFO-তে ম্যাপ হয়, কিন্তু Windows-এ পূর্ণ preemption গ্যারান্টি নাও থাকতে পারে।
2. Ravenscar-এর সীমা:
- Dynamic টাস্ক তৈরি নিষিদ্ধ, তাই সিস্টেম চালুর সময় সব টাস্ক staticভাবে ডিক্লেয়ার করতে হয়। এতে ডিজাইনের স্বাধীনতা কমে।
3. WCET মাপার সীমা:
Ada.Execution_Timeমাপ, গ্যারান্টি নয়। Cache miss বা pipeline hazard সহ সত্যিকারের WCET আলাদা করে static analysis টুল দিয়ে যাচাই করতে হয়।
4. Overhead:
- Protected object-এর barrier মূল্যায়ন entry শেষ বা বাতিল হলে, আর protected object থেকে বেরোলে স্বয়ংক্রিয় চলে। ঘন ঘন ডাকা protected object-এ এই overhead হিসাবে রাখতে হয়।
5. টুলচেইনের বাধা:
- Ada-এর রিয়েল-টাইম ফিচার পুরোপুরি কাজে লাগাতে উপযুক্ত cross-compiler ও runtime লাগে। বিশেষ করে embedded টার্গেটে ভেন্ডর-দেওয়া runtime-এর উপর নির্ভর করতে হয়।
13. সারসংক্ষেপ
এই নিবন্ধে Ada-এর Annex D যে রিয়েল-টাইম ফিচার দেয়, সেগুলো আটটি কোড উদাহরণ দিয়ে ধাপে ধাপে দেখেছি।
| ফিচার | যে মূল্য দেয় |
|---|---|
| টাস্ক priority | Preemptive, priority-ভিত্তিক scheduling |
| Ceiling_Locking | ভাষায় বসানো priority inversion প্রতিরোধ |
delay until |
Cumulative drift ঠেকানো periodic execution |
| Ravenscar profile | Static analysis করা সহজ টাস্ক subset |
| Timing event | Polling ছাড়া সময়চালিত জাগানো |
| Protected কিউ | Protected object-এর barrier-ভিত্তিক সিঙ্ক |
| Execution time পরিমাপ | টাস্কপ্রতি CPU time monitoring |
| মাল্টি-পিরিয়ডিক সমন্বয় | ভিন্ন period-এর টাস্ক নিরাপদে একসঙ্গে রাখার ডিজাইন |
Ada-এর রিয়েল-টাইম ফিচারের সারকথা “পরে জুড়ে দেওয়া নয়“। Priority inversion ঠেকানোর lock নিয়ম, periodic execution-এর সময় নির্দেশ, execution time monitoring—এগুলো ভাষার স্পেসিফিকেশনের অংশ হিসেবে দেওয়া। Deadline পূরণ অবশ্যই ডিজাইন ও বিশ্লেষণে যাচাই করতে হয়, কিন্তু তার ভিত্তি ভাষার runtime গুছিয়ে দেয়—এটাই বড় শক্তি।
পরের ধাপ হিসেবে Ada দিয়ে রিয়েল-টাইম সিস্টেম ডেভেলপমেন্ট নিজে চেষ্টা করতে Alire দিয়ে GNAT টুলচেইন ইনস্টল করে এই নিবন্ধের স্যাম্পল কোড gnatchop + gnatmake দিয়ে বিল্ড করে দেখুন।
Ada concurrency-এর ভিত্তি (টাস্ক, rendezvous, protected object) নিয়ে আগের নিবন্ধ “Ada-তে নিরাপদ concurrency” দেখুন।
14. তথ্যসূত্র
সম্পর্কিত নিবন্ধ
কাছাকাছি বিষয়ে গভীরে যেতে একই ট্যাগযুক্ত সাম্প্রতিক নিবন্ধ।
Ada-তে নিরাপদ concurrency ── টাস্ক ও protected object-এর ব্যবহারিক গাইড
Ada ভাষায় বসানো concurrency—টাস্ক ও protected object—এর পরিচিতিমূলক নিবন্ধ। rendezvous (entry/accept), selective accept, protected objec...
Ada-তে Generic Programming — Type দিয়ে contract লিখে zero-cost reuse
Ada-র generic programming-কে generic subprogram, generic package, formal subprogram, type category ও বাস্তব ডিজাইন নির্দেশিকা পর্যন্ত ধার...
Windows ভার্চুয়ালাইজেশনের গভীরতা (পর্ব ৩) — সেকেন্ডে বুট হওয়া ভার্চুয়াল মেশিন: WSL2, Windows Sandbox ও কন্টেইনার এত হালকা কেন
WSL2 ও Windows Sandbox সেকেন্ডে শুরু হয়ে এত হালকা মনে হয় কেন? এই নিবন্ধ ডায়নামিক বেস ইমেজ ও ডাইরেক্ট ম্যাপ থেকে ডায়নামিক মেমরি বরাদ্দ...
Windows ভার্চুয়ালাইজেশনের গভীরতা (পর্ব ২) — কার্নেলও দেখতে পায় না এমন মেমরি: VBS, HVCI ও Credential Guard কীভাবে কাজ করে
সামঞ্জস্যপূর্ণ হার্ডওয়্যারে ক্লিন ইনস্টলে VBS ডিফল্টে চালু থাকে এবং হাইপারভাইজার ও SLAT দিয়ে কার্নেলের চেয়ে শক্তিশালী আইসোলেশন তৈরি কর...
Windows ভার্চুয়ালাইজেশনের গভীরতা (পর্ব ১) — আপনার Windows আসলে কোথায় চলছে? হাইপারভাইজার ও পার্টিশন
Hyper-V চালু করলে হোস্ট Windows নিজেই রুট পার্টিশন হিসেবে হাইপারভাইজারের উপর চলে। এই নিবন্ধ VT-x, SLAT ও VMBus-এর ভূমিকা দিয়ে ভার্চুয়াল...
সম্পর্কিত বিষয়
এই পৃষ্ঠাগুলো বিষয়টিকে সেবা ও সিদ্ধান্তের বৃহত্তর প্রেক্ষাপটে স্থাপন করে।
Windows-এর প্রযুক্তিগত বিষয়
Windows ডেভেলপমেন্ট, বাগ তদন্ত ও বিদ্যমান সম্পদ ব্যবহারের প্রবেশদ্বার।
প্রায়শ জিজ্ঞাসিত প্রশ্ন
এই নিবন্ধের বিষয়ে পরামর্শে প্রায়ই আসা প্রশ্ন।
- Ada-এর Annex D কী?
- Ada ভাষার স্পেসিফিকেশনের অংশ হিসেবে মানক করা রিয়েল-টাইম সিস্টেমের ফিচারসমূহ। FIFO_Within_Priorities দিয়ে priority-ভিত্তিক preemptive scheduling, priority inversion ঠেকানো Ceiling_Locking protocol, delay until দিয়ে absolute time-এর periodic execution, Ravenscar profile, timing event, আর Ada.Execution_Time দিয়ে টাস্কপ্রতি execution time পরিমাপ এর মধ্যে পড়ে। লাইব্রেরি পরে জুড়ে দেওয়া নয়, ভাষার runtime-এই এগুলো বসানো—এটাই বৈশিষ্ট্য।
- Priority inversion কী? Ada কীভাবে ঠেকায়?
- নিম্ন priority টাস্ক lock ধরে রাখার সময় মধ্যম priority টাস্ক তাকে preempt করে, আর সেই lock-এর অপেক্ষায় থাকা উচ্চ priority টাস্ক অনির্দিষ্টকাল block হয়ে যায়। 1997 সালে Mars Pathfinder-এ এটা সত্যি ঘটেছিল, আর প্রোব বারবার reset হচ্ছিল। Ada-তে Ceiling_Locking protocol ভাষার ফিচার হিসেবে আছে; protected object-এ ঢোকা টাস্ক স্বয়ংক্রিয়ভাবে ceiling priority-তে উঠে যায়, তাই মধ্যম priority টাস্ক তাকে preempt করতে পারে না।
- Ravenscar profile কী?
- যেসব সিস্টেমে নিরাপত্তা অত্যন্ত গুরুত্বপূর্ণ, সেখানে Ada-এর টাস্ক ফিচারকে statically analyzable ও deterministic subset-এ সীমিত করার profile। Dynamic টাস্ক তৈরি, select statement, abort statement, relative delay, requeue statement ইত্যাদি নিষিদ্ধ। এই সীমাবদ্ধতায় static timing analysis সহজ হয়, আর DO-178C (বিমান সফটওয়্যার) বা ISO 26262 (স্বয়ংচালিত functional safety)-এর মতো নিরাপত্তা মানে চাওয়া বৈশিষ্ট্য পূরণ করা সহজ হয়। GNAT-এ gnat.adc ফাইলে pragma Profile (Ravenscar) লিখে চালু করা হয়।
- Periodic টাস্কে delay না লিখে delay until ব্যবহার করার কারণ কী?
- Relative time নির্দেশ করা delay-এ প্রতি iteration-এর processing time যোগ হয়ে period ধীরে ধীরে সরে যায়, অর্থাৎ cumulative drift হয়। delay until absolute time ধরে পরের release time ঠিক করে, তাই একবারের কাজ দেরি হলেও পরের release time ঠিক থাকে। তবে কাজ যদি পরের wake time ছাড়িয়ে যায়, delay until প্রায় সঙ্গে সঙ্গে ফিরে আসে; তাই আলাদা করে deadline miss ধরে overload হিসেবে সামলানোর ডিজাইন দরকার।