Singleton
(মায়ার্স সিঙ্গেলটন) থ্রেডের অলস সূচনাটি ব্যবহার করে নিম্নলিখিত বাস্তবায়ন কি নিরাপদ?
static Singleton& instance()
{
static Singleton s;
return s;
}
যদি তা না হয় তবে কেন এবং কীভাবে এটি থ্রেডটি নিরাপদ করা যায়?
Singleton
(মায়ার্স সিঙ্গেলটন) থ্রেডের অলস সূচনাটি ব্যবহার করে নিম্নলিখিত বাস্তবায়ন কি নিরাপদ?
static Singleton& instance()
{
static Singleton s;
return s;
}
যদি তা না হয় তবে কেন এবং কীভাবে এটি থ্রেডটি নিরাপদ করা যায়?
উত্তর:
ইন সি ++ 11 , এটা থ্রেড নিরাপদ। মতে মান , §6.7 [stmt.dcl] p4
:
ভেরিয়েবলটি আরম্ভ করার সময় যদি নিয়ন্ত্রণ একসাথে ঘোষণায় প্রবেশ করে, একযোগে সম্পাদন শুরুকরণের সমাপ্তির জন্য অপেক্ষা করবে ।
বৈশিষ্ট্যটির জন্য জিসিসি এবং ভিএস সমর্থন ( ডাইনামিক ইনিশিয়েশন এবং কনকুরেন্সি উইথ ডেস্ট্রাকশন , এমএসডিএন-তে ম্যাজিক স্ট্যাটিকস নামে পরিচিত ) নীচে রয়েছে:
তাদের মন্তব্যের জন্য @ মনকারসে এবং @ ওলেন_গ্যামকে ধন্যবাদ।
ইন সি ++ 03 , এই কোড শংকা মুক্ত করা হয় নি। "সি ++ এবং ডাবল-চেকড লকিংয়ের বিপদগুলির" নামে মায়ারদের একটি নিবন্ধ রয়েছে যা প্যাটার্নটির থ্রেড নিরাপদ বাস্তবায়ন সম্পর্কে আলোচনা করে এবং উপসংহারটি আরও কম-বেশি, তা (সি ++ 03 তে) ইনস্ট্যানটিটিং পদ্ধতির চারপাশে সম্পূর্ণ লকিং রয়েছে মূলত সমস্ত প্ল্যাটফর্মে যথাযথ সম্মতি নিশ্চিত করার সহজতম উপায়, যখন বেশিরভাগ ডাবল-চেকড লকিং প্যাটার্ন রূপগুলি নির্দিষ্ট আর্কিটেকচারের রেস শর্তে ভুগতে পারে , যদি না কৌশলগতভাবে মেমরির বাধা না রেখে নির্দেশাবলীকে অন্তর্ভুক্ত করা হয়।
কেন এটি থ্রেডসেফ নয় সে সম্পর্কে আপনার প্রশ্নের উত্তর দেওয়ার জন্য, কারণ এটি নয় যে প্রথম কলটির জন্য instance()
কনস্ট্রাক্টরকে কল করতে হবে Singleton s
। থ্রেডসফেট হওয়ার জন্য এটি একটি সমালোচনামূলক বিভাগে ঘটতে হবে, এবং সমালোচনামূলক বিভাগটি গ্রহণের মানটির কোনও প্রয়োজন নেই (আজকের মান থ্রেডগুলিতে সম্পূর্ণ নীরব) silent সংকলকগণ প্রায়শই একটি সাধারণ চেক এবং স্ট্যাটিক বুলিয়ান বৃদ্ধির সাহায্যে এটি প্রয়োগ করে - তবে একটি সমালোচনামূলক বিভাগে নয়। নিম্নলিখিত সিউডোকোডের মতো কিছু:
static Singleton& instance()
{
static bool initialized = false;
static char s[sizeof( Singleton)];
if (!initialized) {
initialized = true;
new( &s) Singleton(); // call placement new on s to construct it
}
return (*(reinterpret_cast<Singleton*>( &s)));
}
সুতরাং এখানে একটি সাধারণ থ্রেড-নিরাপদ সিঙ্গলটন (উইন্ডোজের জন্য)। এটি উইন্ডোজ CRITICAL_SECTION অবজেক্টের জন্য একটি সাধারণ শ্রেণীর মোড়ক ব্যবহার করে যাতে আমরা সংকলকটি CRITICAL_SECTION
আগে main()
বলা হওয়ার আগে স্বয়ংক্রিয়ভাবে আরম্ভ করতে পারি । আদর্শভাবে একটি সত্য RAII সমালোচনামূলক বিভাগ শ্রেণি ব্যবহার করা হবে যা সমালোচনামূলক বিভাগটি অনুষ্ঠিত হওয়ার পরে ঘটতে পারে এমন ব্যতিক্রমগুলির সাথে মোকাবিলা করতে পারে তবে এটি এই উত্তরটির পরিধি ছাড়িয়ে যায়।
মৌলিক ক্রিয়াকলাপটি হ'ল যখন কোনও উদাহরণটির Singleton
জন্য অনুরোধ করা হয়, একটি লক নেওয়া হয়, সিঙ্গেলটন তৈরি করা হয় যদি এটির প্রয়োজন হয় তবে লকটি প্রকাশ করা হয় এবং সিঙ্গেলটন রেফারেন্স ফিরে আসে।
#include <windows.h>
class CritSection : public CRITICAL_SECTION
{
public:
CritSection() {
InitializeCriticalSection( this);
}
~CritSection() {
DeleteCriticalSection( this);
}
private:
// disable copy and assignment of CritSection
CritSection( CritSection const&);
CritSection& operator=( CritSection const&);
};
class Singleton
{
public:
static Singleton& instance();
private:
// don't allow public construct/destruct
Singleton();
~Singleton();
// disable copy & assignment
Singleton( Singleton const&);
Singleton& operator=( Singleton const&);
static CritSection instance_lock;
};
CritSection Singleton::instance_lock; // definition for Singleton's lock
// it's initialized before main() is called
Singleton::Singleton()
{
}
Singleton& Singleton::instance()
{
// check to see if we need to create the Singleton
EnterCriticalSection( &instance_lock);
static Singleton s;
LeaveCriticalSection( &instance_lock);
return s;
}
মানুষ - "আরও ভাল বিশ্বব্যাপী করতে" এটি প্রচুর বাজে।
এই প্রয়োগের মূল ত্রুটিগুলি (যদি আমি কিছু বাগ স্লিপ না করতাম) তা হ'ল:
new Singleton()
ছুড়ে ফেলে, লকটি প্রকাশ করা হবে না। আমার এখানে থাকা সাধারণটির পরিবর্তে সত্যিকারের আরআইআইআই লক অবজেক্টটি ব্যবহার করে এটি ঠিক করা যেতে পারে। আপনি লস্টের জন্য প্ল্যাটফর্মের স্বতন্ত্র মোড়ক সরবরাহ করতে বুস্টের মতো কিছু ব্যবহার করেন তবে এটি জিনিসগুলি পোর্টেবল করতে সহায়তা করতে পারে।main()
কল করার পরে অনুরোধ করা হলে এটি থ্রেড সুরক্ষার গ্যারান্টি দেয় - যদি আপনি এটির আগে কল করেন (কোনও স্ট্যাটিক অবজেক্টের শুরুতে যেমন) জিনিসগুলি কাজ CRITICAL_SECTION
নাও করতে পারে কারণ সম্ভবত আরম্ভ করা হয়নি।new Singleton()
ছুড়ে মারলে কী হয় ?
new Singleton()
লকটি নিয়ে অবশ্যই সমস্যা থাকে। একটি যথাযথ আরআইআইআই লক ক্লাস ব্যবহার করা উচিত, lock_guard
বুস্টের কাছ থেকে। আমি উদাহরণটি কমবেশি স্ব-অন্তর্নিহিত হতে চেয়েছিলাম এবং এটি ইতিমধ্যে কিছুটা দৈত্য ছিল তাই আমি ব্যতিক্রমী সুরক্ষা ছেড়ে দিয়েছি (তবে এটি বলা হয়েছিল)। হয়তো আমার এটি ঠিক করা উচিত যাতে এই কোডটি অনুপযুক্ত কোথাও কাটা-এন-পেস্ট না হয়।
পরবর্তী স্ট্যান্ডার্ডের (বিভাগ 6.7.4) তাকান, এটি স্থির স্থানীয় সূচনাটি থ্রেড নিরাপদ কী তা ব্যাখ্যা করে। সুতরাং একবার স্ট্যান্ডার্ড বিভাগটি ব্যাপকভাবে প্রয়োগ করা হলে, মায়ারের সিঙ্গলটনই পছন্দসই বাস্তবায়ন হবে।
আমি ইতিমধ্যে অনেক উত্তর সাথে একমত। বেশিরভাগ সংকলক ইতিমধ্যে এইভাবে স্থির সূচনা প্রয়োগ করে। একটি উল্লেখযোগ্য ব্যতিক্রম হ'ল মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও।
নিম্নলিখিত বাস্তবায়ন [...] থ্রেড কি নিরাপদ?
বেশিরভাগ প্ল্যাটফর্মে, এটি থ্রেড-নিরাপদ নয়। (সি -++ স্ট্যান্ডার্ডটি থ্রেড সম্পর্কে জানে না, তাই আইনানুগভাবে এটি এটি কিনা এবং তা তা বলে না বলে সাধারণ অস্বীকৃতি যুক্ত করে যুক্ত করুন))
যদি না হয় তবে কেন [...]?
এটি না হওয়ার কারণটি হ'ল এক সাথে s
'কন্সট্রাক্টর' চালানো থেকে একাধিক থ্রেডকে বাধা দেয় না ।
কিভাবে এটি থ্রেড নিরাপদ করা?
স্কট মায়ারস এবং আন্দ্রে আলেকজান্ড্রেস্কু রচিত "সি ++ এবং পেরিলস অফ ডাবল-চেকড লকিং" থ্রেড-সেফ সিঙ্গেলনসের বিষয়টিতে একটি খুব ভাল গ্রন্থ।
এমসাল্টাররা যেমন বলেছেন: এটি আপনার ব্যবহার করা সি ++ প্রয়োগের উপর নির্ভর করে। ডকুমেন্টেশন চেক করুন। অন্য প্রশ্নের হিসাবে: "যদি না হয় তবে কেন?" - সি ++ স্ট্যান্ডার্ড থ্রেড সম্পর্কে এখনও কিছু উল্লেখ করে না। তবে আসন্ন সি ++ সংস্করণ থ্রেড সম্পর্কে সচেতন এবং এটি স্পষ্টভাবে জানিয়েছে যে স্থির স্থানীয়দের সূচনা থ্রেড-নিরাপদ। যদি দুটি থ্রেড এই জাতীয় ফাংশন কল করে তবে একটি থ্রেড একটি সূচনা করবে যখন অন্যটি ব্লক করবে এবং এটি শেষ হওয়ার জন্য অপেক্ষা করবে।