প্রথমত, আপনাকে কোনও ভাষা আইনজীবির মতো ভাবতে শিখতে হবে।
সি ++ নির্দিষ্টকরণ কোনও নির্দিষ্ট সংকলক, অপারেটিং সিস্টেম বা সিপিইউতে রেফারেন্স তৈরি করে না। এটি একটি বিমূর্ত মেশিনকে উল্লেখ করে যা প্রকৃত সিস্টেমগুলির সাধারণীকরণ। ল্যাঙ্গুয়েজ আইনজীবির বিশ্বে প্রোগ্রামারটির কাজ বিমূর্ত মেশিনের কোড লেখা; সংকলকের কাজটি হল একটি কোডটিকে একটি কংক্রিট মেশিনে বাস্তবায়ন করা। অনুমানের সাথে কঠোরভাবে কোডিং করে আপনি নিশ্চিত হতে পারেন যে আপনার কোডটি কোনও কমপ্লায়েন্ট সি ++ সংকলক সহ যে কোনও সিস্টেমে কোনও পরিবর্তন ছাড়াই সংকলন করবে এবং চলবে, আজ থেকে বা এখন থেকে 50 বছর পরে years
সি ++ 98 / সি ++ 03 স্পেসিফিকেশনের বিমূর্ত মেশিনটি মূলত একক থ্রেডযুক্ত। সুতরাং অনুমানের ক্ষেত্রে "সম্পূর্ণ পোর্টেবল" এমন মাল্টি-থ্রেডেড সি ++ কোড লেখা সম্ভব নয়। মেমরি লোড এবং স্টোরের পারমাণবিকতা বা ক্রম যাতে লোড এবং স্টোরগুলি ঘটতে পারে সে সম্পর্কে ম্যাপেক্স এমনকি কিছু মনে করে না The
অবশ্যই, আপনি নির্দিষ্ট কংক্রিট সিস্টেমের জন্য অনুশীলনে মাল্টি-থ্রেড কোড লিখতে পারেন - যেমন পাইথ্রেড বা উইন্ডোজ। তবে সি ++ 98 / সি ++ 03 এর জন্য মাল্টি-থ্রেড কোড লেখার কোনও মানক উপায় নেই ।
সি ++ 11 এ বিমূর্ত মেশিনটি ডিজাইনের মাধ্যমে বহু-থ্রেডযুক্ত। এটির একটি সুস্পষ্ট সংজ্ঞাযুক্ত মেমরি মডেলও রয়েছে ; এটি হ'ল মেমরি অ্যাক্সেস করার ক্ষেত্রে সংকলকটি কি করতে পারে এবং না পারে তা বলে।
নিম্নলিখিত উদাহরণটি বিবেচনা করুন, যেখানে গ্লোবাল ভেরিয়েবলের একজোড়া একসাথে দুটি থ্রেড দ্বারা অ্যাক্সেস করা হয়:
Global
int x, y;
Thread 1 Thread 2
x = 17; cout << y << " ";
y = 37; cout << x << endl;
থ্রেড 2 আউটপুট কি হতে পারে?
সি ++ 98 / সি ++ 03 এর অধীনে, এটি এমনকি সংজ্ঞায়িত আচরণ নয়; প্রশ্নটি নিজেই অর্থহীন কারণ মানকটি "থ্রেড" বলে কোনও কিছু বিবেচনা করে না।
সি ++ 11 এর অধীনে ফলাফলটি অপরিজ্ঞাত আচরণ, কারণ লোড এবং স্টোরগুলি সাধারণভাবে পারমাণবিক হওয়া দরকার না। যা খুব একটা উন্নতির মতো বলে মনে হচ্ছে না ... এবং নিজে থেকে, তা হয় না।
তবে সি ++ 11 দিয়ে আপনি এটি লিখতে পারেন:
Global
atomic<int> x, y;
Thread 1 Thread 2
x.store(17); cout << y.load() << " ";
y.store(37); cout << x.load() << endl;
এখন বিষয়গুলি আরও আকর্ষণীয় হয়ে উঠেছে। প্রথমত, এখানে আচরণ সংজ্ঞায়িত করা হয় । থ্রেড 2 এখন মুদ্রণ করতে পারে 0 0
(যদি এটি থ্রেড 1 এর আগে চলে), 37 17
(যদি এটি থ্রেড 1 এর পরে চলে) বা 0 17
(যদি এটি থ্রেড 1 এক্স এর পরে নির্ধারিত হয় তবে এটি y নির্ধারিত হওয়ার আগে)।
এটি যা মুদ্রণ করতে পারে না তা হ'ল 37 0
সি ++ 11 এ পারমাণবিক লোড / স্টোরের জন্য ডিফল্ট মোড হ'ল ক্রমযুক্ত ধারাবাহিকতা প্রয়োগ করা । এর অর্থ হ'ল সমস্ত বোঝা এবং স্টোরগুলি অবশ্যই "যেন" হ'ল প্রতিটি থ্রেডের মধ্যে আপনি সেগুলি লিখেছেন এমনভাবে ঘটেছিল, যখন থ্রেডগুলির মধ্যে ক্রিয়াকলাপ আন্তঃবাহিত হতে পারে তবে সিস্টেমটি পছন্দ করে। সুতরাং পারমাণবিকের ডিফল্ট আচরণ লোড এবং স্টোরগুলির জন্য পারমাণবিকতা এবং ক্রম উভয় সরবরাহ করে ।
এখন, একটি আধুনিক সিপিইউতে, ক্রমানুসারে ধারাবাহিকতা নিশ্চিত করা ব্যয়বহুল হতে পারে। বিশেষত, সংকলকটি এখানে প্রতিটি অ্যাক্সেসের মধ্যে পূর্ণ-বিকাশিত মেমরি বাধা নির্গত করতে পারে। তবে যদি আপনার অ্যালগরিদম আউট-অফ-অর্ডার লোড এবং স্টোর সহ্য করতে পারে; অর্থাত্ যদি এটির জন্য পারমাণবিকতা প্রয়োজন তবে অর্ডার না দেওয়া; যেমন, যদি এটি 37 0
এই প্রোগ্রাম থেকে আউটপুট হিসাবে সহ্য করতে পারে তবে আপনি এটি লিখতে পারেন:
Global
atomic<int> x, y;
Thread 1 Thread 2
x.store(17,memory_order_relaxed); cout << y.load(memory_order_relaxed) << " ";
y.store(37,memory_order_relaxed); cout << x.load(memory_order_relaxed) << endl;
সিপিইউ যত বেশি আধুনিক, এটি পূর্বের উদাহরণের চেয়ে তত দ্রুত হওয়ার সম্ভাবনা রয়েছে।
শেষ অবধি, আপনার যদি কেবল নির্দিষ্ট বোঝা এবং স্টোরগুলিকে যথাযথভাবে রাখতে হয় তবে আপনি লিখতে পারেন:
Global
atomic<int> x, y;
Thread 1 Thread 2
x.store(17,memory_order_release); cout << y.load(memory_order_acquire) << " ";
y.store(37,memory_order_release); cout << x.load(memory_order_acquire) << endl;
এটি আমাদের অর্ডার করা লোড এবং স্টোরগুলিতে ফিরিয়ে নিয়ে যায় - সুতরাং 37 0
আর কোনও সম্ভাব্য আউটপুট হয় না - তবে এটি ন্যূনতম ওভারহেডের সাথে করে। (এই তুচ্ছ উদাহরণে, ফলাফলটি সম্পূর্ণ-প্রস্ফুটিত ধারাবাহিক ধারাবাহিকতার মতো; বৃহত্তর প্রোগ্রামে এটি হবে না))
অবশ্যই, আপনি দেখতে চাইলে কেবলমাত্র আউটপুটগুলি হ'ল 0 0
বা 37 17
, আপনি কেবলমাত্র মূল কোডটির চারপাশে একটি মিটেক্স মোড়তে পারেন। তবে আপনি যদি এখন পর্যন্ত এটি পড়ে থাকেন তবে আমি বাজি ধরছি যে এটি কীভাবে কাজ করে তা আপনি ইতিমধ্যে জানেন এবং এই উত্তরটি আমার ইচ্ছা :-) অপেক্ষা ইতিমধ্যে দীর্ঘ।
সুতরাং, নীচের লাইন। মিউটেক্সগুলি দুর্দান্ত, এবং সি ++ 11 এগুলিকে মানায়। তবে কখনও কখনও কর্মক্ষমতা কারণে আপনি নিম্ন স্তরের আদিম (যেমন ক্লাসিক ডাবল-চেকড লকিং ধরণ ) চান। নতুন স্ট্যান্ডার্ডটি উচ্চ স্তরের গ্যাজেটগুলি যেমন মাইটেক্সেস এবং শর্ত ভেরিয়েবলগুলি সরবরাহ করে এবং এটি নিম্ন স্তরের গ্যাজেটগুলি যেমন পারমাণবিক ধরণের এবং মেমরি বাধার বিভিন্ন স্বাদ সরবরাহ করে। সুতরাং এখন আপনি মানক দ্বারা নির্দিষ্ট ভাষার মধ্যে পরিশীলিত, উচ্চ-পারফরম্যান্স সমকালীন রুটিনগুলি সম্পূর্ণরূপে লিখতে পারেন এবং আপনি নিশ্চিত হতে পারেন যে আপনার কোডটি আজকের সিস্টেম এবং আগামীকাল উভয় ক্ষেত্রেই সংকলন এবং অপরিবর্তিতভাবে চলবে।
যদিও খোলামেলা বলার অপেক্ষা রাখে না, আপনি যদি বিশেষজ্ঞ না হন এবং কিছু গুরুতর নিম্ন-স্তরের কোডে কাজ না করেন তবে আপনার সম্ভবত মুটিক্স এবং শর্তের পরিবর্তনশীলগুলিতে লেগে থাকা উচিত। এটাই আমি করার ইচ্ছা করি।
এই স্টাফ উপর আরও জানতে, এই ব্লগ পোস্ট দেখুন ।