সিঙ্গলটন প্যাটার্ন থ্রেডের কি মায়ার্সের প্রয়োগ নিরাপদ?


145

Singleton(মায়ার্স সিঙ্গেলটন) থ্রেডের অলস সূচনাটি ব্যবহার করে নিম্নলিখিত বাস্তবায়ন কি নিরাপদ?

static Singleton& instance()
{
     static Singleton s;
     return s;
}

যদি তা না হয় তবে কেন এবং কীভাবে এটি থ্রেডটি নিরাপদ করা যায়?


কেউ দয়া করে ব্যাখ্যা করতে পারেন কেন এটি থ্রেড নিরাপদ নয়। লিঙ্কগুলিতে উল্লিখিত নিবন্ধগুলিতে বিকল্প বাস্তবায়ন (পয়েন্টার ভেরিয়েবল অর্থাৎ স্ট্যাটিক সিঙ্গলটন * পিনস্ট্যান্স) ব্যবহার করে থ্রেড সুরক্ষা নিয়ে আলোচনা করা হয়েছে।
অঙ্কুর



উত্তর:


168

ইন সি ++ 11 , এটা থ্রেড নিরাপদ। মতে মান , §6.7 [stmt.dcl] p4:

ভেরিয়েবলটি আরম্ভ করার সময় যদি নিয়ন্ত্রণ একসাথে ঘোষণায় প্রবেশ করে, একযোগে সম্পাদন শুরুকরণের সমাপ্তির জন্য অপেক্ষা করবে

বৈশিষ্ট্যটির জন্য জিসিসি এবং ভিএস সমর্থন ( ডাইনামিক ইনিশিয়েশন এবং কনকুরেন্সি উইথ ডেস্ট্রাকশন , এমএসডিএন-তে ম্যাজিক স্ট্যাটিকস নামে পরিচিত ) নীচে রয়েছে:

তাদের মন্তব্যের জন্য @ মনকারসে এবং @ ওলেন_গ্যামকে ধন্যবাদ।


ইন সি ++ 03 , এই কোড শংকা মুক্ত করা হয় নি। "সি ++ এবং ডাবল-চেকড লকিংয়ের বিপদগুলির" নামে মায়ারদের একটি নিবন্ধ রয়েছে যা প্যাটার্নটির থ্রেড নিরাপদ বাস্তবায়ন সম্পর্কে আলোচনা করে এবং উপসংহারটি আরও কম-বেশি, তা (সি ++ 03 তে) ইনস্ট্যানটিটিং পদ্ধতির চারপাশে সম্পূর্ণ লকিং রয়েছে মূলত সমস্ত প্ল্যাটফর্মে যথাযথ সম্মতি নিশ্চিত করার সহজতম উপায়, যখন বেশিরভাগ ডাবল-চেকড লকিং প্যাটার্ন রূপগুলি নির্দিষ্ট আর্কিটেকচারের রেস শর্তে ভুগতে পারে , যদি না কৌশলগতভাবে মেমরির বাধা না রেখে নির্দেশাবলীকে অন্তর্ভুক্ত করা হয়।


3
মডার্ন সি ++ ডিজাইনে আলেকজান্দ্রেস্কু কর্তৃক সিঙ্গলটন প্যাটার্ন (আজীবন এবং থ্রেডসফটি) নিয়েও বিস্তৃত আলোচনা রয়েছে। লোকির সাইট দেখুন: loki-lib.sourceforge.net/index.php?n=Pattern.Singleton
এম।

1
আপনি বুস্ট :: কল_অনসেস দিয়ে একটি থ্রেড-সেফ সিঙ্গলটন তৈরি করতে পারেন।
নগদকাহ

1
দুর্ভাগ্যক্রমে, স্ট্যান্ডার্ডটির এই অংশটি ভিজ্যুয়াল স্টুডিও 2012 সি ++ সংকলকটিতে প্রয়োগ করা হয়নি। "সি ++ 11 মূল ভাষার বৈশিষ্ট্যগুলি: সমঝোতা" টেবিলটিতে "ম্যাজিক স্ট্যাটিক্স" হিসাবে উল্লেখ করা হয়েছে: এমএসডিএন.ইমক্রোসফটি.এইন
লিবেরি

মান থেকে প্রাপ্ত স্নিপেটটি নির্মাণকে সম্বোধন করে তবে ধ্বংস নয় not অন্য থ্রেডে প্রোগ্রামের সমাপ্তির সময় অন্য থ্রেডটিতে অ্যাক্সেস করার চেষ্টা করার সময় মানটি কী কোনও থ্রেডে ধ্বংস হওয়া থেকে আটকাতে পারে?
স্টুবাসিক

আইএএনএ (সি ++ ভাষা) এল তবে বিভাগ ৩.6.৩ [বেসিক.স্টার্ট.মিটার] পি 2 পরামর্শ দেয় যে অবজেক্টটি ধ্বংস হয়ে যাওয়ার পরে অ্যাক্সেস করার চেষ্টা করে অপরিজ্ঞাত আচরণ করা সম্ভব?
স্টুবাসিক

21

কেন এটি থ্রেডসেফ নয় সে সম্পর্কে আপনার প্রশ্নের উত্তর দেওয়ার জন্য, কারণ এটি নয় যে প্রথম কলটির জন্য 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নাও করতে পারে কারণ সম্ভবত আরম্ভ করা হয়নি।
  • প্রতিটি বার অনুরোধ করার সময় একটি লক অবশ্যই নেওয়া উচিত be আমি যেমন বলেছি, এটি একটি সহজ থ্রেড নিরাপদ বাস্তবায়ন। আপনার যদি আরও ভাল প্রয়োজন হয় (বা ডাবল-চেক লক কৌশলটির মতো জিনিসগুলি কেন ত্রুটিযুক্ত তা জানতে চান), গ্রোয়ের উত্তরে লিঙ্কিত কাগজপত্রগুলি দেখুন ।

1
আহ ওহ. new Singleton()ছুড়ে মারলে কী হয় ?
এসবিআই

@ بابি - যথাযথ লাইব্রেরির সাথে সেট করার জন্য, নন-অনুলিপি এবং একটি উপযুক্ত আরআইআই লক থাকা সমস্ত ক্রাফ্টটি চলে যাবে বা ন্যূনতম হবে। তবে আমি চেয়েছিলাম উদাহরণটি যুক্তিযুক্তভাবে স্বনির্ভর হোক। যদিও সিঙ্গলটনগুলি খুব কম লাভের জন্য অনেক কাজ, তবে আমি তাদের গ্লোবালের ব্যবহার পরিচালনায় দরকারী বলে মনে করেছি। তারা যখন নামকরণের কনভেনশন থেকে কিছুটা বেশি এবং কখন ব্যবহৃত হয় তখন এটি সন্ধান করা আরও সহজ করে তোলে।
মাইকেল মুর বার

@ এসবিআই: এই উদাহরণে, যদি new Singleton()লকটি নিয়ে অবশ্যই সমস্যা থাকে। একটি যথাযথ আরআইআইআই লক ক্লাস ব্যবহার করা উচিত, lock_guardবুস্টের কাছ থেকে। আমি উদাহরণটি কমবেশি স্ব-অন্তর্নিহিত হতে চেয়েছিলাম এবং এটি ইতিমধ্যে কিছুটা দৈত্য ছিল তাই আমি ব্যতিক্রমী সুরক্ষা ছেড়ে দিয়েছি (তবে এটি বলা হয়েছিল)। হয়তো আমার এটি ঠিক করা উচিত যাতে এই কোডটি অনুপযুক্ত কোথাও কাটা-এন-পেস্ট না হয়।
মাইকেল বারার 18

কেন গতিশীলভাবে সিঙ্গলটন বরাদ্দ? শুধু 'পিআইএনস্ট্যান্স' কে 'সিঙ্গলটন :: দৃষ্টান্ত ()' এর স্থির সদস্য হিসাবে তৈরি করবেন না কেন?
মার্টিন ইয়র্ক

@ মার্টিন - সম্পন্ন আপনি ঠিক বলেছেন, এটি কিছুটা সহজ করে তোলে - আমি যদি আরএআইআই লক ক্লাস ব্যবহার করি তবে আরও ভাল হয়।
মাইকেল বুড় 22

10

পরবর্তী স্ট্যান্ডার্ডের (বিভাগ 6.7.4) তাকান, এটি স্থির স্থানীয় সূচনাটি থ্রেড নিরাপদ কী তা ব্যাখ্যা করে। সুতরাং একবার স্ট্যান্ডার্ড বিভাগটি ব্যাপকভাবে প্রয়োগ করা হলে, মায়ারের সিঙ্গলটনই পছন্দসই বাস্তবায়ন হবে।

আমি ইতিমধ্যে অনেক উত্তর সাথে একমত। বেশিরভাগ সংকলক ইতিমধ্যে এইভাবে স্থির সূচনা প্রয়োগ করে। একটি উল্লেখযোগ্য ব্যতিক্রম হ'ল মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও।


6

সঠিক উত্তরটি আপনার সংকলকের উপর নির্ভর করে। এটি বর্তমানে এমন সিদ্ধান্ত নিতে পারেন করতে এটা threadsafe; এটি "প্রাকৃতিকভাবে" থ্রেডসেফ নয়।


5

নিম্নলিখিত বাস্তবায়ন [...] থ্রেড কি নিরাপদ?

বেশিরভাগ প্ল্যাটফর্মে, এটি থ্রেড-নিরাপদ নয়। (সি -++ স্ট্যান্ডার্ডটি থ্রেড সম্পর্কে জানে না, তাই আইনানুগভাবে এটি এটি কিনা এবং তা তা বলে না বলে সাধারণ অস্বীকৃতি যুক্ত করে যুক্ত করুন))

যদি না হয় তবে কেন [...]?

এটি না হওয়ার কারণটি হ'ল এক সাথে s'কন্সট্রাক্টর' চালানো থেকে একাধিক থ্রেডকে বাধা দেয় না ।

কিভাবে এটি থ্রেড নিরাপদ করা?

স্কট মায়ারস এবং আন্দ্রে আলেকজান্ড্রেস্কু রচিত "সি ++ এবং পেরিলস অফ ডাবল-চেকড লকিং" থ্রেড-সেফ সিঙ্গেলনসের বিষয়টিতে একটি খুব ভাল গ্রন্থ।


2

এমসাল্টাররা যেমন বলেছেন: এটি আপনার ব্যবহার করা সি ++ প্রয়োগের উপর নির্ভর করে। ডকুমেন্টেশন চেক করুন। অন্য প্রশ্নের হিসাবে: "যদি না হয় তবে কেন?" - সি ++ স্ট্যান্ডার্ড থ্রেড সম্পর্কে এখনও কিছু উল্লেখ করে না। তবে আসন্ন সি ++ সংস্করণ থ্রেড সম্পর্কে সচেতন এবং এটি স্পষ্টভাবে জানিয়েছে যে স্থির স্থানীয়দের সূচনা থ্রেড-নিরাপদ। যদি দুটি থ্রেড এই জাতীয় ফাংশন কল করে তবে একটি থ্রেড একটি সূচনা করবে যখন অন্যটি ব্লক করবে এবং এটি শেষ হওয়ার জন্য অপেক্ষা করবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.