Thread Synchronization এবং Data Sharing হল মাল্টি-থ্রেডেড প্রোগ্রামিংয়ের দুটি অত্যন্ত গুরুত্বপূর্ণ ধারণা, যা একাধিক থ্রেডের মধ্যে নিরাপদভাবে ডেটা প্রবাহ এবং সমন্বয় নিশ্চিত করে। থ্রেডিং প্রোগ্রামিংয়ে একাধিক থ্রেড একই ডেটাকে অ্যাক্সেস করতে পারে, এবং যদি সেগুলো সঠিকভাবে সমন্বিত না হয়, তাহলে data corruption বা race conditions ঘটতে পারে। এই সমস্যাগুলো সমাধান করতে synchronization এবং locking mechanisms ব্যবহৃত হয়।
রুবি (Ruby) ভাষায়, Thread Synchronization এবং Data Sharing এর জন্য কিছু বিশেষ মেকানিজম রয়েছে, যেমন Mutex, Monitor, এবং ConditionVariable। এখানে, আমরা এই বিষয়গুলো বিস্তারিতভাবে আলোচনা করব।
১. Thread Synchronization in Ruby
Thread Synchronization হল এমন একটি কৌশল যার মাধ্যমে একাধিক থ্রেডের মধ্যে একসাথে কাজ করার সময় ডেটার নিরাপত্তা নিশ্চিত করা হয়। যখন একাধিক থ্রেড একই ডেটার উপরে কাজ করে, তখন সেগুলোর মধ্যে race conditions এবং data corruption হতে পারে। এই ধরনের সমস্যা এড়াতে mutex বা monitor ব্যবহার করা হয়, যা শুধুমাত্র একটি থ্রেডকে একে একে ডেটা অ্যাক্সেস করার অনুমতি দেয়।
১.১ Mutex (Mutual Exclusion)
Mutex (Mutual Exclusion) একটি লক যা এক থ্রেডকে একটি নির্দিষ্ট কোড ব্লক অ্যাক্সেস করার অনুমতি দেয় এবং অন্য থ্রেডকে সেটি অ্যাক্সেস করতে বাধা দেয় যতক্ষণ না প্রথম থ্রেড কাজটি শেষ করে।
উদাহরণ:
require 'thread'
mutex = Mutex.new
# Shared resource
counter = 0
# Creating two threads
threads = []
2.times do
threads << Thread.new do
1000.times do
mutex.synchronize do
counter += 1
end
end
end
end
# Waiting for threads to finish
threads.each(&:join)
puts counter # Output should be 2000 (ensuring no race condition)এখানে, mutex.synchronize ব্লকটি একটি লক তৈরি করেছে, যার মাধ্যমে শুধুমাত্র একটি থ্রেড একে একে counter ভেরিয়েবল অ্যাক্সেস করতে পারবে। ফলে, race condition রোধ করা হয়েছে এবং ডেটার নিরাপত্তা নিশ্চিত করা হয়েছে।
১.২ Monitor
Monitor রুবির একটি অতিরিক্ত ক্লাস যা mutex এর চেয়ে কিছুটা বেশি সুবিধাজনক, কারণ এটি মিথস্ক্রিয়া এবং অবরোধ সমাধানের জন্য আরও উন্নত ফিচার প্রদান করে। Monitor ব্যবহার করলে আপনার কোড আরও সহজে এবং পরিষ্কারভাবে লেখা যায়।
উদাহরণ:
require 'monitor'
monitor = Monitor.new
counter = 0
threads = []
2.times do
threads << Thread.new do
1000.times do
monitor.synchronize do
counter += 1
end
end
end
end
threads.each(&:join)
puts counter # Output should be 2000এখানে, monitor.synchronize ব্যবহার করে থ্রেডগুলির মধ্যে নিরাপদ সমন্বয় নিশ্চিত করা হয়েছে। এটি mutex এর মতোই কাজ করে, তবে কিছু ক্ষেত্রে এটি আরও সুবিধাজনক হতে পারে।
২. Data Sharing Between Threads
Data Sharing হল একাধিক থ্রেডের মধ্যে ডেটা শেয়ার করার প্রক্রিয়া। যদিও একাধিক থ্রেড একই ডেটাকে শেয়ার করতে পারে, কিন্তু যদি সেই ডেটা অ্যাক্সেস করার সময় সঠিক সমন্বয় না থাকে, তাহলে data inconsistency হতে পারে। এর সমাধান হিসেবে mutex, condition variables, এবং queues ব্যবহার করা হয়।
২.১ Condition Variables
Condition Variables একটি থ্রেডের জন্য অপেক্ষা (wait) করার বা অন্য থ্রেডের কোনো পরিবর্তন হওয়ার পর কাজ করতে পারে। এটি মূলত থ্রেডের মধ্যে সিঙ্ক্রোনাইজেশন প্রক্রিয়া করতে ব্যবহৃত হয়, যেখানে একটি থ্রেড অন্য থ্রেডের কার্যাবলী সম্পন্ন হওয়ার জন্য অপেক্ষা করে।
উদাহরণ:
require 'thread'
mutex = Mutex.new
condition = ConditionVariable.new
counter = 0
# Consumer thread
consumer = Thread.new do
mutex.synchronize do
condition.wait(mutex) while counter == 0 # Wait until counter > 0
puts "Consumed: #{counter}"
end
end
# Producer thread
producer = Thread.new do
mutex.synchronize do
counter = 10 # Produce data
condition.signal # Signal the consumer thread
end
end
consumer.join
producer.joinএখানে, condition.wait থ্রেডকে একটি শর্ত পূর্ণ না হওয়া পর্যন্ত অপেক্ষা করতে বলে, এবং condition.signal অন্য থ্রেডকে সিগন্যাল পাঠায়, যার ফলে সে কাজটি শুরু করতে পারে। এটি synchronization নিশ্চিত করার জন্য ব্যবহৃত হয়।
৩. Queue for Data Sharing
রুবি থ্রেডিংয়ে Queue একটি খুবই কার্যকরী ডেটা শেয়ারিং মেকানিজম, যেখানে এক থ্রেড enqueue (অর্থাৎ ডেটা যুক্ত) করে এবং অন্য থ্রেড সেই ডেটা dequeue (অর্থাৎ বের করে) করতে পারে। এটি থ্রেডের মধ্যে সিঙ্ক্রোনাইজড ডেটা শেয়ার করতে ব্যবহৃত হয়।
উদাহরণ:
require 'thread'
queue = Queue.new
# Producer thread
producer = Thread.new do
5.times do |i|
queue.push(i) # Push data into the queue
puts "Produced: #{i}"
end
end
# Consumer thread
consumer = Thread.new do
5.times do
item = queue.pop # Pop data from the queue
puts "Consumed: #{item}"
end
end
producer.join
consumer.joinএখানে, Queue একটি থ্রেড থেকে আরেক থ্রেডে ডেটা শেয়ার করার জন্য ব্যবহার করা হয়েছে। থ্রেডগুলো enqueue এবং dequeue করে ডেটা শেয়ার করেছে। Queue এর নিজস্ব ইন্টারনাল সিঙ্ক্রোনাইজেশন রয়েছে, তাই এটি থ্রেড সেফ (thread-safe)।
সারসংক্ষেপ
- Thread Synchronization হল এমন একটি কৌশল যার মাধ্যমে একাধিক থ্রেড একই ডেটার উপরে কাজ করার সময় সঠিক সমন্বয় এবং নিরাপত্তা নিশ্চিত করা হয়। Mutex, Monitor, এবং ConditionVariable এই উদ্দেশ্যে ব্যবহৃত হয়।
- Mutex থ্রেডের মধ্যে একসাথে একই কোড ব্লক অ্যাক্সেস করা থেকে বিরত রাখে।
- Monitor একটি উন্নত সিঙ্ক্রোনাইজেশন মেকানিজম, যা mutex এর মত কাজ করে তবে আরও অনেক ফিচার দিয়ে থাকে।
- Condition Variables থ্রেডগুলোর মধ্যে সিঙ্ক্রোনাইজেশন এবং একটি থ্রেডকে অন্য থ্রেডের কাজ সম্পন্ন হওয়ার জন্য অপেক্ষা করতে সাহায্য করে।
- Queue থ্রেডের মধ্যে ডেটা শেয়ার করতে ব্যবহৃত হয়, যেখানে এক থ্রেড ডেটা যোগ (enqueue) করে এবং অন্য থ্রেড তা বের (dequeue) করে।
এই কৌশলগুলি একে অপরের সাথে সমন্বিতভাবে কাজ করে এবং মাল্টি-থ্রেডেড প্রোগ্রামিংকে আরো কার্যকর, নিরাপদ এবং সিঙ্ক্রোনাইজড করে তোলে।
Read more