ওহে! আপনি যখন CodeGym-এ মাল্টিথ্রেডিং অধ্যয়ন করেছেন, আপনি প্রায়শই "mutex" এবং "monitor" ধারণার সম্মুখীন হয়েছেন। উঁকি না দিয়ে, আপনি বলতে পারেন কিভাবে তারা আলাদা? :) যদি হ্যাঁ, ভাল কাজ! যদি তা না হয় (এটি সবচেয়ে সাধারণ), এতে অবাক হওয়ার কিছু নেই। "Mutex" এবং "মনিটর" আসলে সম্পর্কিত ধারণা। অতিরিক্তভাবে, আপনি যখন পাঠগুলি পড়েন এবং অন্যান্য ওয়েবসাইটে মাল্টিথ্রেডিং সম্পর্কে ভিডিওগুলি দেখেন, তখন আপনি আরেকটি অনুরূপ ধারণা দেখতে পাবেন: "সেমাফোর"। মনিটর এবং মিউটেক্সের সাথে এটির খুব অনুরূপ ফাংশন রয়েছে। তাই আমরা এই তিনটি পদের তদন্ত করতে যাচ্ছি। আমরা কয়েকটি উদাহরণ দেখব এবং এই ধারণাগুলি একে অপরের থেকে কীভাবে আলাদা তা একটি নির্দিষ্ট বোঝার জন্য আসব :)
মিউটেক্স
একটি মিউটেক্স (বা লক) থ্রেড সিঙ্ক্রোনাইজ করার জন্য একটি বিশেষ প্রক্রিয়া। একটি জাভাতে প্রতিটি বস্তুর সাথে "সংযুক্ত" - আপনি ইতিমধ্যেই জানেন যে :) আপনি যদি স্ট্যান্ডার্ড ক্লাস ব্যবহার করেন বা আপনার নিজস্ব ক্লাস তৈরি করেন তবে এটি কোন ব্যাপার না, যেমন Cat এবং Dog : সমস্ত ক্লাসের সমস্ত বস্তুর একটি mutex আছে । "মিউটেক্স" শব্দটি "মিউচুয়াল এক্সক্লুশন" থেকে এসেছে, যা এর উদ্দেশ্যকে পুরোপুরি বর্ণনা করে। যেমনটি আমরা আমাদের পূর্ববর্তী পাঠের একটিতে বলেছি, একটি মিউটেক্স এটি নিশ্চিত করা সম্ভব করে যে একবারে শুধুমাত্র একটি থ্রেড বস্তুটিতে অ্যাক্সেস রয়েছে। মিউটেক্সের একটি জনপ্রিয় বাস্তব-জীবনের উদাহরণ হল টয়লেট জড়িত। যখন একজন ব্যক্তি টয়লেট পার্টিশনে প্রবেশ করেন, তখন তিনি ভেতর থেকে দরজা বন্ধ করে দেন। টয়লেট একটি বস্তুর মত যা একাধিক থ্রেড দ্বারা অ্যাক্সেস করা যেতে পারে। পার্টিশনের দরজার তালাটি একটি মিউটেক্সের মতো, এবং বাইরের লোকদের লাইন থ্রেডের প্রতিনিধিত্ব করে। দরজার তালা হল টয়লেটের মিউটেক্স: এটি নিশ্চিত করে যে শুধুমাত্র একজন ব্যক্তি ভিতরে প্রবেশ করতে পারে। অন্য কথায়, এক সময়ে শুধুমাত্র একটি থ্রেড ভাগ করা সম্পদের সাথে কাজ করতে পারে। দখলকৃত সম্পদে অ্যাক্সেস পাওয়ার জন্য অন্যান্য থ্রেডের (লোকেদের) প্রচেষ্টা ব্যর্থ হবে। একটি মিউটেক্সের বেশ কয়েকটি গুরুত্বপূর্ণ বৈশিষ্ট্য রয়েছে। প্রথমত , শুধুমাত্র দুটি অবস্থা সম্ভব: "আনলক" এবং "লক করা"। এটি কীভাবে কাজ করে তা আমাদের বুঝতে সাহায্য করে: আপনি বুলিয়ান ভেরিয়েবল (সত্য/মিথ্যা) বা বাইনারি সংখ্যা (0/1) এর সাথে সমান্তরাল আঁকতে পারেন। রাষ্ট্রকে সরাসরি নিয়ন্ত্রণ করা যায় না। জাভাতে এমন কোন ব্যবস্থা নেই যা আপনাকে স্পষ্টভাবে একটি বস্তু নিতে, এর মিউটেক্স পেতে এবং পছন্দসই স্থিতি বরাদ্দ করতে দেয়। অন্য কথায়, আপনি এরকম কিছু করতে পারবেন না:
Object myObject = new Object();
Mutex mutex = myObject.getMutex();
mutex.free();
এর মানে হল যে আপনি একটি বস্তুর mutex প্রকাশ করতে পারবেন না। শুধুমাত্র জাভা মেশিনের সরাসরি অ্যাক্সেস আছে। প্রোগ্রামাররা ভাষার টুলের মাধ্যমে মিউটেক্সের সাথে কাজ করে।
মনিটর
একটি মনিটর একটি মিউটেক্সের উপর একটি অতিরিক্ত "সুপারস্ট্রাকচার"। আসলে, একটি মনিটর হল কোডের একটি অংশ যা প্রোগ্রামারের কাছে "অদৃশ্য"। আমরা যখন মিউটেক্স সম্পর্কে আগে কথা বলেছিলাম, তখন আমরা একটি সাধারণ উদাহরণ দিয়েছিলাম:
public class Main {
private Object obj = new Object();
public void doSomething() {
// ...some logic, available for all threads
synchronized (obj) {
// Logic available to just one thread at a time
}
}
}
সিঙ্ক্রোনাইজড কীওয়ার্ড দিয়ে চিহ্নিত কোড ব্লকে , আমাদের obj অবজেক্টের মিউটেক্স অর্জিত হয়। দুর্দান্ত, আমরা লকটি অর্জন করতে পারি, তবে কীভাবে "সুরক্ষা" দেওয়া হয়? যখন আমরা শব্দটি সিঙ্ক্রোনাইজড দেখি , তখন অন্য থ্রেডগুলিকে ব্লকে প্রবেশ করতে বাধা দেয় কী? সুরক্ষা একটি মনিটর থেকে আসে! কম্পাইলার সিঙ্ক্রোনাইজড কীওয়ার্ডকে কোডের কয়েকটি বিশেষ অংশে রূপান্তর করে। আবার, আসুন doSomething() পদ্ধতির সাথে আমাদের উদাহরণে ফিরে আসি। আমরা এটি যোগ করব:
public class Main {
private Object obj = new Object();
public void doSomething() {
// ...some logic, available for all threads
// Logic available to just one thread at a time
synchronized (obj) {
/* Do important work that requires that the object
be accessed by only one thread */
obj.someImportantMethod();
}
}
}
কম্পাইলার এই কোডটি রূপান্তর করার পরে "হুডের নীচে" যা ঘটে তা এখানে:
public class Main {
private Object obj = new Object();
public void doSomething() throws InterruptedException {
// ...some logic, available for all threads
// Logic available to just one thread at a time:
/* as long as the object's mutex is busy,
all the other threads (except the one that acquired it) are put to sleep */
while (obj.getMutex().isBusy()) {
Thread.sleep(1);
}
// Mark the object's mutex as busy
obj.getMutex().isBusy() = true;
/* Do important work that requires that the object
be accessed by only one thread */
obj.someImportantMethod();
// Free the object's mutex
obj.getMutex().isBusy() = false;
}
}
অবশ্যই, এটি একটি বাস্তব উদাহরণ নয়। এখানে, আমরা জাভা মেশিনের ভিতরে কী ঘটছে তা চিত্রিত করতে জাভা-এর মতো কোড ব্যবহার করেছি। এটি বলেছিল, এই ছদ্ম-কোডটি সিঙ্ক্রোনাইজড ব্লকের ভিতরে বস্তু এবং থ্রেডগুলির সাথে আসলে কী ঘটে এবং কীভাবে কম্পাইলার এই কীওয়ার্ডটিকে প্রোগ্রামারের কাছে "অদৃশ্য" বেশ কয়েকটি বিবৃতিতে রূপান্তর করে তার একটি দুর্দান্ত বোঝার দেয়। মূলত, জাভা একটি মনিটরের প্রতিনিধিত্ব করতে সিঙ্ক্রোনাইজড কীওয়ার্ড ব্যবহার করে । শেষ উদাহরণে সিঙ্ক্রোনাইজড কীওয়ার্ডের পরিবর্তে প্রদর্শিত সমস্ত কোড হল মনিটর।
সেমাফোর
মাল্টিথ্রেডিং সম্পর্কে আপনার ব্যক্তিগত অধ্যয়নে আপনি যে আরেকটি শব্দের মুখোমুখি হবেন তা হল "সেমাফোর"। আসুন এটি কী এবং এটি একটি মনিটর এবং মিউটেক্স থেকে কীভাবে আলাদা তা খুঁজে বের করা যাক। সেমাফোর হল কিছু রিসোর্সে অ্যাক্সেস সিঙ্ক্রোনাইজ করার একটি টুল। এর স্বতন্ত্র বৈশিষ্ট্য হল এটি সিঙ্ক্রোনাইজেশন মেকানিজম তৈরি করতে একটি কাউন্টার ব্যবহার করে। কাউন্টারটি আমাদের বলে যে কতগুলি থ্রেড একসাথে ভাগ করা সম্পদ অ্যাক্সেস করতে পারে। জাভাতে Semaphores সেমাফোর ক্লাস দ্বারা প্রতিনিধিত্ব করা হয়। সেমাফোর অবজেক্ট তৈরি করার সময়, আমরা নিম্নলিখিত কনস্ট্রাক্টরগুলি ব্যবহার করতে পারি:
Semaphore(int permits)
Semaphore(int permits, boolean fair)
আমরা কনস্ট্রাক্টরের কাছে নিম্নলিখিতগুলি প্রেরণ করি:
- বুলিয়ান ফেয়ার — থ্রেড অ্যাক্সেস লাভ করবে এমন ক্রম স্থাপন করে। যদি ন্যায্যতা সত্য হয়, তাহলে ওয়েটিং থ্রেডগুলিতে অ্যাক্সেস দেওয়া হয় যে ক্রমে তারা অনুরোধ করেছিল। যদি এটি মিথ্যা হয়, তাহলে অর্ডারটি থ্রেড শিডিউলারের দ্বারা নির্ধারিত হয়।
class Philosopher extends Thread {
private Semaphore sem;
// Did the philosopher eat?
private boolean full = false;
private String name;
Philosopher(Semaphore sem, String name) {
this.sem=sem;
this.name=name;
}
public void run()
{
try
{
// If the philosopher has not eaten
if (!full) {
// Ask the semaphore for permission to run
sem.acquire();
System.out.println(name + " takes a seat at the table");
// The philosopher eats
sleep(300);
full = true;
System.out.println(name + " has eaten! He leaves the table");
sem.release();
// The philosopher leaves, making room for others
sleep(300);
}
}
catch(InterruptedException e) {
System.out.println("Something went wrong!");
}
}
}
এবং এখানে আমাদের প্রোগ্রাম চালানোর কোড আছে:
public class Main {
public static void main(String[] args) {
Semaphore sem = new Semaphore(2);
new Philosopher(sem, "Socrates").start();
new Philosopher(sem,"Plato").start();
new Philosopher(sem,"Aristotle").start();
new Philosopher(sem, "Thales").start();
new Philosopher(sem, "Pythagoras").start();
}
}
আমরা একটি সেমাফোর তৈরি করেছি যার কাউন্টারটি শর্ত পূরণ করার জন্য 2 সেট করা হয়েছে: শুধুমাত্র দুইজন দার্শনিক একই সময়ে খেতে পারেন। অর্থাৎ, একই সময়ে শুধুমাত্র দুটি থ্রেড চলতে পারে, কারণ আমাদের দার্শনিক শ্রেণীর থ্রেড উত্তরাধিকারসূত্রে পাওয়া যায় ! সেমাফোর ক্লাসের acquire () এবং release() পদ্ধতিগুলি এর অ্যাক্সেস কাউন্টার নিয়ন্ত্রণ করে। acquire() পদ্ধতি সেমাফোরকে রিসোর্সে অ্যাক্সেসের জন্য জিজ্ঞাসা করে। যদি কাউন্টারটি >0 হয়, তবে অ্যাক্সেস মঞ্জুর করা হয় এবং কাউন্টারটি 1 দ্বারা হ্রাস করা হয়। মুক্তি ()পদ্ধতিটি পূর্বে দেওয়া অ্যাক্সেস "রিলিজ" করে, কাউন্টারে ফিরিয়ে দেয় (সেমাফোরের অ্যাক্সেস কাউন্টারকে 1 দ্বারা বৃদ্ধি করে)। আমরা প্রোগ্রাম চালানোর সময় আমরা কি পেতে পারি? সমস্যা কি সমাধান হয়েছে? আমাদের দার্শনিকরা কি তাদের পালার অপেক্ষায় যুদ্ধ করবেন না? :) এখানে আমরা পেয়েছিলাম কনসোল আউটপুট:
Socrates takes a seat at the table
Plato takes a seat at the table
Socrates has eaten! He leaves the table
Plato has eaten! He leaves the table
Aristotle takes a seat at the table
Pythagoras takes a seat at the table
Aristotle has eaten! He leaves the table
Pythagoras has eaten! He leaves the table
Thales takes a seat at the table
Thales has eaten! He leaves the table
আমরা এটা করেছি! এবং যদিও থ্যালেসকে একাই খেতে হয়েছিল, আমি মনে করি না যে আমরা তাকে অসন্তুষ্ট করেছি :) আপনি একটি মিউটেক্স এবং সেমাফোরের মধ্যে কিছু মিল লক্ষ্য করেছেন। প্রকৃতপক্ষে, তাদের একই লক্ষ্য রয়েছে: কিছু সংস্থানে অ্যাক্সেস সিঙ্ক্রোনাইজ করা। শুধুমাত্র পার্থক্য হল যে একটি বস্তুর মিউটেক্স একটি সময়ে শুধুমাত্র একটি থ্রেড দ্বারা অধিগ্রহণ করা যেতে পারে, যখন একটি সেমাফোরের ক্ষেত্রে, যা একটি থ্রেড কাউন্টার ব্যবহার করে, বেশ কয়েকটি থ্রেড একই সাথে সংস্থান অ্যাক্সেস করতে পারে। এটি কেবল একটি কাকতালীয় ঘটনা নয় :) একটি মিউটেক্স আসলে একটি সেমাফোর1 এর গণনা সহ। অন্য কথায়, এটি একটি সেমাফোর যা একটি একক থ্রেড মিটমাট করতে পারে। এটি একটি "বাইনারী সেমাফোর" নামেও পরিচিত কারণ এর কাউন্টারে মাত্র 2টি মান থাকতে পারে — 1 ("আনলক করা") এবং 0 ("লক করা")। এটাই! আপনি দেখতে পাচ্ছেন, এটি এতটা বিভ্রান্তিকর নয় :) এখন, আপনি যদি ইন্টারনেটে আরও বিশদে মাল্টিথ্রেডিং অধ্যয়ন করতে চান তবে এই ধারণাগুলি নেভিগেট করা আপনার পক্ষে কিছুটা সহজ হবে। পরবর্তী পাঠে দেখা হবে!
GO TO FULL VERSION