Concurrency Control এবং Deadlock হল multithreading এবং parallel processing এ অত্যন্ত গুরুত্বপূর্ণ ধারণা। এগুলি বিভিন্ন থ্রেডের মধ্যে সিঙ্ক্রোনাইজেশন এবং নির্দিষ্ট পরিস্থিতিতে বিভিন্ন থ্রেডের মধ্যে সমন্বয় প্রক্রিয়া নিয়ন্ত্রণ করে।
১. Concurrency Control (সংকেত নিয়ন্ত্রণ)
Concurrency Control হল এমন একটি প্রক্রিয়া যা একাধিক থ্রেড বা প্রসেসের মধ্যে সিঙ্ক্রোনাইজেশন এবং ডেটা এক্সেসের সময়ের সঠিক সমন্বয় নিশ্চিত করে। যখন একাধিক থ্রেড একই ডেটা স্ট্রাকচার বা রিসোর্সের উপর একযোগে কাজ করে, তখন ডেটার অখণ্ডতা (data integrity) বজায় রাখা অত্যন্ত গুরুত্বপূর্ণ। Concurrency Control সঠিকভাবে পরিচালিত না হলে data inconsistency এবং race conditions হতে পারে।
Concurrency Control এর প্রধান উদ্দেশ্য হল:
- একাধিক থ্রেড বা প্রসেসের মধ্যে সঠিক সমন্বয় নিশ্চিত করা।
- ডেটার একাধিক থ্রেডের দ্বারা পরিবর্তনের সময় সমস্যা এড়ানো (যেমন, Race Condition এবং Atomicity রক্ষা করা)।
- একাধিক থ্রেড বা প্রসেসের মধ্যে সমন্বয় করা যাতে তারা নির্ভরযোগ্যভাবে কাজ করতে পারে।
Concurrency Control এর জন্য ব্যবহৃত পদ্ধতিসমূহ:
- Mutexes (Mutual Exclusion): একাধিক থ্রেড একই সময়ে একটি নির্দিষ্ট রিসোর্স অ্যাক্সেস করতে না পারে, সেজন্য তাদের মধ্যে mutexes ব্যবহার করা হয়।
- Locks: Locking ব্যবহার করে থ্রেড গুলোকে একে একে রিসোর্স অ্যাক্সেস করতে দেওয়া হয়।
- Reentrant Lock: জাভার
ReentrantLockক্লাস, যা আরও বেশি নিয়ন্ত্রণ এবং সিঙ্ক্রোনাইজেশনের সুবিধা দেয়।
- Reentrant Lock: জাভার
- Semaphore: এটি একটি কনকারেন্ট প্রোগ্রামিং কনসেপ্ট, যা একটি নির্দিষ্ট সংখ্যক থ্রেডকে একই রিসোর্স অ্যাক্সেস করতে দেয়।
- Synchronized Blocks: একটি ব্লক বা মেথড শুধুমাত্র এক থ্রেডের দ্বারা এক্সিকিউট করার জন্য synchronized কীওয়ার্ড ব্যবহার করা হয়।
উদাহরণ: Synchronized Method in Java
class Counter {
private int count = 0;
// Synchronized method to ensure only one thread accesses it at a time
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public int getCount() {
return count;
}
}
public class ConcurrencyExample {
public static void main(String[] args) {
Counter counter = new Counter();
// Thread 1 - Incrementing counter
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
});
// Thread 2 - Decrementing counter
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.decrement();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// Final count after both threads have completed their execution
System.out.println("Final count: " + counter.getCount());
}
}
ব্যাখ্যা:
synchronizedkeyword: এটি নিশ্চিত করে যে শুধুমাত্র একটি থ্রেড একে একে increment() এবং decrement() মেথড অ্যাক্সেস করবে।join()method: এটি থ্রেডের এক্সিকিউশনের শেষে মেইন থ্রেডে ফিরে আসার আগে অপেক্ষা করে।
২. Deadlock (ডেডলক)
Deadlock হল একটি পরিস্থিতি যেখানে দুটি বা তার বেশি থ্রেড একে অপরের জন্য অপেক্ষা করে, এবং কোন থ্রেডই সম্পূর্ণ হতে পারে না। সাধারণভাবে, deadlock ঘটতে পারে যদি দুটি বা তার বেশি থ্রেড এমনভাবে লক পান যে তারা একে অপরের রিসোর্সের জন্য অপেক্ষা করে, কিন্তু তাদেরকে মুক্তি দেওয়া হয় না।
Deadlock এর সাধারণ শর্তসমূহ (Conditions for Deadlock):
- Mutual Exclusion: প্রতিটি রিসোর্স শুধুমাত্র এক থ্রেডের দ্বারা ব্যবহৃত হতে পারে।
- Hold and Wait: একটি থ্রেড এক বা একাধিক রিসোর্স ধরে রাখে এবং অন্য রিসোর্সের জন্য অপেক্ষা করে।
- No Preemption: একবার একটি থ্রেড একটি রিসোর্স নিয়ে নেয়, তখন অন্য থ্রেড সেই রিসোর্সটি ছিনিয়ে নিতে পারে না।
- Circular Wait: একাধিক থ্রেডের মধ্যে একটি চক্রের সৃষ্টি হয়, যেখানে প্রত্যেক থ্রেড পরবর্তী থ্রেডের জন্য অপেক্ষা করে।
উদাহরণ: Deadlock in Java
class A {
synchronized void methodA(B b) {
System.out.println("Thread 1: Locked A, waiting for B");
b.last();
}
synchronized void last() {
System.out.println("Inside A's last method");
}
}
class B {
synchronized void methodB(A a) {
System.out.println("Thread 2: Locked B, waiting for A");
a.last();
}
synchronized void last() {
System.out.println("Inside B's last method");
}
}
public class DeadlockExample {
public static void main(String[] args) {
final A a = new A();
final B b = new B();
// Thread 1
Thread t1 = new Thread(() -> a.methodA(b));
// Thread 2
Thread t2 = new Thread(() -> b.methodB(a));
t1.start();
t2.start();
}
}
ব্যাখ্যা:
- এখানে দুটি থ্রেড একে অপরের রিসোর্সের জন্য অপেক্ষা করছে। থ্রেড 1
methodA()তেAলক করে এবং তারপরBএর জন্য অপেক্ষা করে। একইভাবে, থ্রেড 2methodB()তেBলক করে এবং তারপরAএর জন্য অপেক্ষা করে। এই কারণে deadlock ঘটে, এবং কোন থ্রেডই এগোতে পারে না।
৩. Deadlock Prevention and Resolution
Deadlock প্রতিরোধ এবং সমাধানের জন্য কিছু কৌশল রয়েছে:
- Deadlock Prevention: Deadlock প্রতিরোধ করতে, উপরের শর্তগুলির মধ্যে কোনো একটি শর্ত এড়িয়ে যেতে হবে। যেমন:
- Avoid Hold and Wait: থ্রেডগুলি সম্পূর্ণভাবে সমস্ত রিসোর্স গ্রহণ না করা পর্যন্ত কোনও রিসোর্স গ্রহণ করতে পারে না।
- Avoid Circular Wait: রিসোর্সগুলিকে একটি নির্দিষ্ট ক্রমে বরাদ্দ করতে হবে যাতে circular wait এর পরিস্থিতি না ঘটে।
- Deadlock Detection: Deadlock ঘটে গেলে সিস্টেম এটি শনাক্ত করতে পারে এবং থ্রেডগুলিকে পুনরায় পুনরায় চালাতে পারে।
- Deadlock Recovery: Deadlock ঘটলে, সিস্টেম থ্রেডগুলির মধ্যে একটিকে সিলেক্ট করে তাকে বাতিল করতে পারে বা থ্রেডগুলির একটির এক্সিকিউশন থামিয়ে দেয়।
সারাংশ
- Concurrency Control: একাধিক থ্রেডের মধ্যে সিঙ্ক্রোনাইজেশন নিশ্চিত করার জন্য locks, mutexes, semaphores, এবং synchronized blocks ব্যবহার করা হয়।
- Deadlock: একটি অবস্থা যেখানে দুটি বা ততোধিক থ্রেড একে অপরের রিসোর্সের জন্য অপেক্ষা করে, এবং কোন থ্রেডই শেষ করতে পারে না। Deadlock এড়ানোর জন্য deadlock prevention, detection, এবং recovery কৌশল প্রয়োগ করা হয়।
Read more