Semaphore একটি সিঙ্ক্রোনাইজেশন প্রিমিটিভ যা কাউন্টার এবং অপেক্ষমাণ থ্রেডের সারির মাধ্যমে একটি শেয়ার্ড রিসোর্সে অ্যাক্সেস নিয়ন্ত্রণ করে। Wikipedia, 2024 অনুসারে, সেমাফোরটি এডসগার ডিজক্সট্রা 1965 সালে মাল্টিথ্রেডেড ইন্টারঅ্যাকশন সমস্যা সমাধানের জন্য প্রস্তাব করেছিলেন। টুলটি ক্রিটিকাল সেকশনের সাথে একই সাথে কাজ করা থ্রেডের সংখ্যা সীমিত করতে দেয়।
মূল পয়েন্ট
Semaphore একটি সিঙ্ক্রোনাইজেশন প্রিমিটিভ যা একটি শেয়ার্ড রিসোর্সে অ্যাক্সেস নিয়ন্ত্রণের জন্য কাউন্টার ব্যবহার করে। ধারণাটি এডসগার ডিজক্সট্রা 1965 সালে প্রস্তাব করেছিলেন এবং এটি অপারেটিং সিস্টেমের সমস্ত আধুনিক সিঙ্ক্রোনাইজেশন মেকানিজমের ভিত্তি হয়ে ওঠে।
সেমাফোর হল দুটি পারমাণবিক অপারেশন সহ একটি পূর্ণসংখ্যা চলক: wait (acquire) এবং signal (release)। wait অপারেশন কাউন্টার হ্রাস করে, যখন signal এটি বৃদ্ধি করে। যখন কাউন্টার শূন্যে পৌঁছায়, wait কলকারী থ্রেডটি ব্লক হয়ে যায় যতক্ষণ না অন্য থ্রেড signal সম্পাদন করে।
সেমাফোরের মূল উদ্দেশ্য হল একাধিক থ্রেডের একসাথে অ্যাক্সেস থেকে ক্রিটিকাল সেকশন রক্ষা করা। মিউটেক্সের বিপরীতে, সেমাফোরের মালিক থ্রেডের সাথে আবদ্ধতা প্রয়োজন হয় না, যা এটিকে বিস্তৃত সমন্বয় কাজের জন্য উপযুক্ত করে তোলে।
সেমাফোরের ধারণাটি THE অপারেটিং সিস্টেমের প্রসঙ্গে উদ্ভূত হয়েছিল, যা Technische Hogeschool Eindhoven-এ বিকশিত হয়েছিল। ডিজক্সট্রা সেমাফোরকে একটি গাণিতিক বিমূর্ততা হিসেবে আনুষ্ঠানিক রূপ দিয়েছিলেন, যেকোনো সিঙ্ক্রোনাইজেশন প্রিমিটিভ বাস্তবায়নের জন্য এর পর্যাপ্ততা প্রমাণ করেছিলেন।
সেমাফোর মেকানিজম দুটি পারমাণবিক অপারেশন এবং একটি অভ্যন্তরীণ অপেক্ষা সারির উপর ভিত্তি করে। যখন acquire কল করা হয়, থ্রেড কাউন্টারের মান পরীক্ষা করে এবং হয় কার্যকরী চালিয়ে যায় অথবা রিসোর্স মুক্ত না হওয়া পর্যন্ত ব্লক হয়।
সেমাফোর তৈরি করার সময়, অনুমতি কাউন্টারের একটি প্রাথমিক মান নির্ধারণ করা হয়। প্রতিটি acquire কল কাউন্টার 1 দ্বারা হ্রাস করে। যদি এর পরে কাউন্টার ঋণাত্মক হয়, থ্রেড ব্লক হয়ে যায়। release অপারেশন কাউন্টার বৃদ্ধি করে এবং অপেক্ষমাণ থ্রেডগুলোর একটিকে জাগিয়ে তোলে।
import java.util.concurrent.Semaphore
val semaphore = Semaphore(3)
fun accessResource() {
semaphore.acquire()
try {
println("${Thread.currentThread().name} কাজ করছে")
} finally {
semaphore.release()
}
}
যখন একটি থ্রেড শূন্য কাউন্টার নিয়ে acquire কল করে, OS এটি সেমাফোরের FIFO সারিতে রাখে। থ্রেড BLOCKED অবস্থায় চলে যায়, CPU সময় ব্যবহার করে না। release কলের পর, সারির প্রথম থ্রেড RUNNABLE অবস্থায় যায় এবং রিসোর্সে অ্যাক্সেস পায়।
সিঙ্ক্রোনাইজেশন তত্ত্বে সেমাফোরের দুটি প্রধান প্রকার পৃথক করা হয়: বাইনারি এবং কাউন্টিং। প্রকারের পছন্দ রিসোর্সে অ্যাক্সেস ব্যবস্থাপনার নির্দিষ্ট কাজের উপর নির্ভর করে।
বাইনারি সেমাফোর শুধুমাত্র মান 0 এবং 1 নেয়। আচরণে, এটি মিউটেক্সের মতো, কিন্তু মালিকানার প্রয়োজন ছাড়া — যেকোনো থ্রেড release সম্পাদন করতে পারে। এই ধরনের সেমাফোর থ্রেডের মধ্যে প্রস্তুতি ফ্ল্যাগ এবং ইভেন্ট বাস্তবায়নের জন্য সুবিধাজনক।
val ready = Semaphore(0)
fun producer() {
Thread.sleep(1000)
ready.release()
}
fun consumer() {
ready.acquire()
println("ডেটা প্রস্তুত")
}
কাউন্টিং সেমাফোর যেকোনো অ-ঋণাত্মক মান নিতে পারে। এটি একই ধরনের রিসোর্সের পুল পরিচালনার জন্য ব্যবহৃত হয় যেখানে একাধিক ইনস্ট্যান্স উপলব্ধ। উদাহরণস্বরূপ, ৫টি নেটওয়ার্ক সংযোগের পুল: প্রতিটি acquire একটি সংযোগ নেয়, release এটি পুলে ফিরিয়ে দেয়।
কাউন্টিং সেমাফোর বাহ্যিক সার্ভিসে অ্যাক্সেসের গতি সীমিত করতে এবং থ্রেড পুল বাস্তবায়নের জন্য অপরিহার্য। এগুলো ম্যানুয়াল থ্রেড ব্যবস্থাপনা ছাড়াই সমান্তরালতার মাত্রা সঠিকভাবে নিয়ন্ত্রণ করতে দেয়।
| প্যারামিটার | বাইনারি সেমাফোর | কাউন্টিং সেমাফোর |
|---|---|---|
| পরিসর | 0 বা 1 | 0 থেকে N |
| একসাথে থ্রেড | 1 | N পর্যন্ত |
| প্রয়োগ | সংকেত, ফ্ল্যাগ | রিসোর্স পুল, গতি সীমা |
ডেভেলপাররা প্রায়ই সেমাফোর এবং মিউটেক্সকে গুলিয়ে ফেলেন, যদিও এদের মধ্যে মৌলিক পার্থক্য রয়েছে। এই পার্থক্যগুলি বোঝা একটি প্রকল্পে সঠিক সিঙ্ক্রোনাইজেশন মেকানিজম নির্বাচনের জন্য অত্যন্ত গুরুত্বপূর্ণ।
মূল পার্থক্য হল মালিকানা ধারণা। মিউটেক্স সর্বদা জানে কোন থ্রেড এটি অর্জন করেছে, এবং শুধুমাত্র সেই থ্রেড এটি মুক্ত করতে পারে। সেমাফোরের কোনো মালিক নেই: যেকোনো থ্রেড acquire না করেও release কল করতে পারে। এটি মিউটেক্সকে ডেটা সুরক্ষার জন্য নিরাপদ এবং সেমাফোরকে সমন্বয়ের জন্য আরও নমনীয় করে তোলে।
অনুশীলনে, মিউটেক্স সাধারণ পরিস্থিতির অপ্টিমাইজেশনের কারণে সহজ পারস্পরিক বর্জনের জন্য দ্রুততর। সেমাফোরের কাউন্টার বজায় রাখতে অতিরিক্ত ওভারহেড প্রয়োজন। তবে, সমান্তরালতা সীমিত করতে বা উৎপাদক-ভোক্তা প্যাটার্ন বাস্তবায়নের জন্য, সেমাফোর অপরিহার্য।
| বৈশিষ্ট্য | Semaphore | Mutex |
|---|---|---|
| মালিকানা | কোনো মালিক নেই | মালিক আছে |
| মুক্তি | যেকোনো থ্রেড | শুধুমাত্র মালিক থ্রেড |
| কাউন্টার | 0 থেকে N | বাইনারি |
| ব্যবহার ক্ষেত্র | সমান্তরালতা সীমা এবং সংকেত | ক্রিটিকাল সেকশন সুরক্ষা |
| পুনরাবৃত্তি | না | হ্যাঁ (পুনঃপ্রবেশযোগ্য) |
মোবাইল অ্যাপ্লিকেশন ডেভেলপমেন্টে, Semaphore সীমিত রিসোর্সে অ্যাক্সেস পরিচালনার জন্য ব্যবহৃত হয়: নেটওয়ার্ক সংযোগ, ফাইল, ডেটাবেস এবং হার্ডওয়্যার উপাদান। আধুনিক প্ল্যাটফর্মগুলি সুবিধাজনক অন্তর্নির্মিত বাস্তবায়ন প্রদান করে।
একটি সাধারণ ব্যবহারের ক্ষেত্র হল HTTP সংযোগ পুল। একটি অ্যাপ্লিকেশন সার্ভারে একসাথে সর্বোচ্চ ৪টি অনুরোধ পাঠাতে পারে কারণ প্রদানকারীর API সমান্তরালতা সীমিত করে। প্রাথমিক মান ৪ সহ একটি সেমাফোর নিশ্চিত করে যে যেকোনো লোডের অধীনে, সমবর্তী অনুরোধের সংখ্যা সীমা অতিক্রম না করে, অন্য থ্রেডগুলি সারিতে অপেক্ষা করে।
সেমাফোর ছাড়া, ব্যবহারকারীর কার্যকলাপে তীব্র বৃদ্ধি সার্ভার পরিকাঠামোতে হঠাৎ ওভারলোড সৃষ্টি করতে পারে, যা টাইমআউট এবং 429 Too Many Requests ত্রুটির দিকে নিয়ে যায়। Semaphore ফিউজের মতো কাজ করে, সক্রিয় থ্রেডের সংখ্যা নির্বিশেষে কঠোরভাবে নির্দিষ্ট সংখ্যক সমবর্তী কলের অনুমতি দেয়।
Android java.util.concurrent প্যাকেজ থেকে Semaphore ক্লাস প্রদান করে। আসুন সার্ভার ওভারলোড প্রতিরোধের জন্য সমবর্তী নেটওয়ার্ক অনুরোধ দুটি থ্রেডে সীমিত করার উদাহরণ দেখি।
class ApiClient {
private val throttle = Semaphore(2)
suspend fun fetch(url: String): Result {
throttle.acquire()
return try {
httpGet(url)
} finally {
throttle.release()
}
}
}
iOS এ, GCD থেকে DispatchSemaphore একই কাজ সমাধান করে। ডেভেলপাররা প্রধান থ্রেড ব্লক না করে অ্যাসিঙ্ক্রোনাস কোডে রিসোর্সে অ্যাক্সেস সিঙ্ক্রোনাইজ করতে এটি ব্যবহার করেন।
let semaphore = DispatchSemaphore(value: 3)
func processBatch(_ items: [UIImage]) {
for img in items {
semaphore.wait()
DispatchQueue.global().async {
applyFilter(to: img)
semaphore.signal()
}
}
}
সবচেয়ে সাধারণ ভুল হল ব্যতিক্রমের সময় ভুলে যাওয়া release। যদি একটি থ্রেড release কল করার আগে ত্রুটির সাথে শেষ হয়, সেমাফোরটি অন্যান্য থ্রেডের জন্য স্থায়ীভাবে ব্লক থেকে যায়। নিশ্চিত মুক্তির জন্য try/finally বা defer ব্যবহার করুন। দ্বিতীয় সমস্যা হল বিভিন্ন থ্রেড দ্বারা ভিন্ন ক্রমে একাধিক সেমাফোর অর্জনের সময় deadlock।
সেমাফোর শুধুমাত্র ডেটা সুরক্ষার জন্য নয়, জটিল মাল্টিথ্রেডেড পরিস্থিতিতে থ্রেড সমন্বয়ের জন্যও ব্যবহৃত হয়। সাধারণ প্যাটার্ন জানা ডেভেলপমেন্ট দ্রুত করে এবং সিঙ্ক্রোনাইজেশন ত্রুটির সম্ভাবনা হ্রাস করে।
বাস্তব প্রকল্পে সেমাফোর ব্যবহারের বেশ কয়েকটি প্রমাণিত প্যাটার্ন রয়েছে। এগুলো জানা সাধারণ ভুল এড়াতে এবং নির্ভরযোগ্য মাল্টিথ্রেডেড সিস্টেম তৈরি করতে সাহায্য করে।
প্রাথমিক মান N এবং টাইমারের মাধ্যমে পর্যায়ক্রমিক release সহ একটি সেমাফোর API অনুরোধের গতি সীমা বাস্তবায়ন করে। উদাহরণস্বরূপ, একটি সার্ভিস প্রতি সেকেন্ডে ১০টি অনুরোধের অনুমতি দেয়: সেমাফোর ১০ থেকে শুরু হয়, প্রতিটি অনুরোধ কাউন্টার হ্রাস করে, এবং একটি পৃথক TimerTask প্রতি সেকেন্ডে কাউন্টারকে তার প্রাথমিক মানে ফিরিয়ে আনে। এটি অ্যাপ্লিকেশন এবং সার্ভার উভয়কেই ওভারলোড থেকে রক্ষা করে।
ক্লাসিক উৎপাদক-ভোক্তা সমস্যায়, দুটি সেমাফোর একটি বাফার পরিচালনা করে: empty (লেখার অনুমতি) এবং full (পড়ার অনুমতি)। উৎপাদক empty তে acquire এবং full এ release কল করে, যখন ভোক্তা বিপরীত করে। এই স্কিম নিশ্চিত করে যে ভোক্তা কখনই খালি বাফার পড়ে না এবং উৎপাদক কখনই এটি ওভারফ্লো করে না।
এই একই স্কিম অপারেটিং সিস্টেমে বাউন্ডেড বাফারের — নির্দিষ্ট আকারের রিং বাফারের ভিত্তি। মোবাইল অ্যাপ্লিকেশনে, প্যাটার্নটি ছবি, ভিডিও ফাইল এবং বিশ্লেষণাত্মক ইভেন্টের সারি প্রক্রিয়াকরণের জন্য ব্যবহৃত হয়।
সেমাফোর সফলভাবে ব্যাকগ্রাউন্ড সার্ভিসে নেটওয়ার্ক কল থ্রটলিং এর জন্য ব্যবহৃত হয়। উদাহরণস্বরূপ, একটি বিশ্লেষণ অ্যাপ্লিকেশন সার্ভারে ইভেন্ট প্যাকেট পাঠায়। পিক লোডের সময় (অ্যাপ চালু, অফলাইনের পর সিঙ্ক্রোনাইজেশন) সমবর্তী থ্রেড সীমিত না করলে, একসাথে অনুরোধের সংখ্যা সার্ভার সীমা অতিক্রম করতে পারে। প্রাথমিক মান ৩ সহ একটি সেমাফোর মসৃণ প্রেরণ নিশ্চিত করে এবং সার্ভার-সাইড ব্লকিং প্রতিরোধ করে।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Semaphore শুধু একটি কাউন্টার নয়, বরং পারমাণবিক অপারেশন এবং অপেক্ষা সারি সহ একটি সিঙ্ক্রোনাইজেশন প্রিমিটিভ। সাধারণ কাউন্টার থ্রেড ব্লক করে না এবং একাধিক থ্রেডের একসাথে অ্যাক্সেসের সময় পারমাণবিক বৃদ্ধির নিশ্চয়তা দেয় না।
হ্যাঁ, deadlock সম্ভব যখন বিভিন্ন থ্রেড দ্বারা ভিন্ন ক্রমে একাধিক সেমাফোর অর্জিত হয়। উদাহরণস্বরূপ, থ্রেড A S1, তারপর S2 অর্জন করে, যখন থ্রেড B S2, তারপর S1 অর্জন করে। প্রকল্পের সমস্ত সেমাফোরের জন্য একটি একক অর্জন ক্রম নির্ধারণ করুন।
থ্রেড ব্লক হয় এবং অপেক্ষা অবস্থায় যায়। এটি অন্য থ্রেড release কল না করা পর্যন্ত CPU সময় ব্যবহার করে না। Java এ, এটি BLOCKED অবস্থা; Swift এ, থ্রেড GCD দ্বারা স্থগিত করা হয়।
প্রধান পার্থক্য হল মালিকানা। Mutex কেবল মালিক থ্রেড দ্বারা মুক্ত করা যায়। Binary Semaphore যেকোনো থ্রেড দ্বারা মুক্ত করা যায়, যা থ্রেডের মধ্যে সংকেতের জন্য সুবিধাজনক কিন্তু ডেটা অখণ্ডতা রক্ষার জন্য কম নিরাপদ।
প্রাথমিক মান পরিস্থিতির উপর নির্ভর করে। একটি একক রিসোর্স রক্ষার জন্য — 1। N সংযোগের পুলের জন্য — N। থ্রেডের মধ্যে সংকেতের জন্য, 0 ব্যবহার করুন যাতে ভোক্তা থ্রেড উৎপাদকের কাছ থেকে সংকেতের জন্য অপেক্ষা করে।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন