2012-04-05 2 views
2

Если мне нужно написать одноэлементный класс в C++, я буду использовать статическую переменную, частный конструктор & public static function, который возвращает объект класса. Однако в многопоточных средах код будет иметь проблемы. Чтобы избежать одновременного доступа к нескольким потокам одной и той же переменной, лучше всего использовать механизм синхронизации Boost для синхронизации? Я имею в виду установку/снятие блокировки/мьютекса через ресурс. Есть ли что-нибудь еще встроенное в стандартной библиотеке C++, где мне не нужно загружать boost, build stuff и т. Д.? Я слышал о C++ Ox, но не знаю много.Singleton Synchronization C++

ответ

7

C++ 98/03 не имеет ничего, чтобы поддерживать потоки вообще. Если вы используете компилятор C++ 98 или 03, вы в значительной степени зацикливаетесь на использовании Boost или чего-то (более или менее) для ОС, таких как pthreads или примитивы Win32 для потоковой передачи.

C++ 11 имеет достаточно полную библиотеку поддержки нити, с мьютексы, замки, локальной памяти потока и т.д.

Я чувствую себя обязанным отметить, однако, что может быть лучше для резервного копирования и немного поразмышляйте о том, нужен ли вам/нужен Синглтон вообще. Положительно, синглтонная модель в значительной степени не понравилась.

Редактировать: Перечитывая это, я как бы пропустил одну вещь, которую я хотел сказать: по крайней мере, когда я их использовал, все/все синглеты были полностью инициализированы до того, как был запущен какой-либо вторичный поток. Это оказывает беспокойство по поводу безопасности потока в их инициализации полностью спорно. Я предполагаю, что может быть один сингл, который вы не можете инициализировать, прежде чем запускать второстепенные потоки, поэтому вам нужно будет справиться с этим, но, по крайней мере, сразу же это кажется мне довольно необычным исключением, с которым я имел бы дело только тогда, когда/если это абсолютно необходимо.

+0

Я не видел ничего, чтобы предположить, что одноэлементный шаблон выпал из употребления у практических практиков. (Конечно, он никогда не использовался широко среди них. Только тогда, когда это необходимо, что не так часто.) –

+0

Я видел много «Синглтона», но ни один из них не нужен. Просто сделайте это и передайте его. –

+0

Грубо говоря: «Singleton» - это, как правило, ошибка дизайна. Хотя ... Я согласен, что это удобно для схем регистрации (гораздо больше, чем передача объекта Logger в каждой отдельной функции). –

0

Для меня лучший способ реализовать синглтон с помощью C++ 11 является:

class Singleton 
{ 
public: 
static Singleton & Instance() 
{ 
    // Since it's a static variable, if the class has already been created, 
    // It won't be created again. 
    // And it **is** thread-safe in C++11. 

    static Singleton myInstance; 

    // Return a reference to our instance. 
    return myInstance; 
} 

// delete copy and move constructors and assign operators 
Singleton(Singleton const&) = delete;    // Copy construct 
Singleton(Singleton&&) = delete;     // Move construct 
Singleton& operator=(Singleton const&) = delete; // Copy assign 
Singleton& operator=(Singleton &&) = delete;  // Move assign 

// Any other public methods 

protected: 
Singleton() 
{ 
    // Constructor code goes here. 
} 

~Singleton() 
{ 
    // Destructor code goes here. 
} 

// And any other protected methods. 
} 

Это C++ 11 функции, но с этим, как вы можете создать потокобезопасные Singleton. Согласно новому стандарту, больше не нужно заботиться об этой проблеме. Инициализация объекта будет выполняться только одним потоком, другие потоки будут ждать завершения. Или вы можете использовать std :: call_once.

Если вы хотите сделать эксклюзивный доступ к ресурсам синглтона, вам необходимо использовать блокировку для этих функций.

Различный тип замков:

Использование atomic_flg_lck:

class SLock 
{ 
public: 
    void lock() 
    { 
    while (lck.test_and_set(std::memory_order_acquire)); 
    } 

    void unlock() 
    { 
    lck.clear(std::memory_order_release); 
    } 

    SLock(){ 
    //lck = ATOMIC_FLAG_INIT; 
    lck.clear(); 
    } 
private: 
    std::atomic_flag lck;// = ATOMIC_FLAG_INIT; 
}; 

Использование атомарным

class SLock 
{ 
public: 
    void lock() 
    { 
    while (lck.exchange(true)); 
    } 

    void unlock() 
    { 
    lck = true; 
    } 

    SLock(){ 
    //lck = ATOMIC_FLAG_INIT; 
    lck = false; 
    } 
private: 
    std::atomic<bool> lck; 
}; 

Использование семафор:

class SLock 
{ 
public: 
    void lock() 
    { 
    lck.lock(); 
    } 

    void unlock() 
    { 
    lck.unlock(); 
    } 

private: 
    std::mutex lck; 
}; 

Только для Окно:

class SLock 
{ 
public: 
    void lock() 
    { 
    EnterCriticalSection(&g_crit_sec); 
    } 

    void unlock() 
    { 
    LeaveCriticalSection(&g_crit_sec); 
    } 

    SLock(){ 
    InitializeCriticalSectionAndSpinCount(&g_crit_sec, 0x80000400); 
    } 

private: 
    CRITICAL_SECTION g_crit_sec; 
}; 

атомного и и atomic_flg_lck держать нить в счете спины. Mutex просто спит нить. Если время ожидания слишком длинное, возможно, лучше спать поток.Последний «CRITICAL_SECTION» удерживает поток в расчете количества спинов до тех пор, пока не будет потреблено время, затем нить переходит в режим сна.

Как использовать эти критические разделы?

unique_ptr<SLock> raiilock(new SLock()); 

class Smartlock{ 
public: 
    Smartlock(){ raiilock->lock(); } 
    ~Smartlock(){ raiilock->unlock(); } 
}; 

Использование идиомы raii. Конструктор блокирует критический раздел и деструктор, чтобы разблокировать его.

Пример

class Singleton { 

    void syncronithedFunction(){ 
     Smartlock lock; 
     //..... 
    } 

} 

Этой реализация является безопасной нитью и исключения безопасна, так как переменная блокировки сохраняется в стеке так, когда область видимости функции закончилась (конец функции или исключения) деструктор будет называться.

Я надеюсь, что вы найдете это полезным.

Спасибо!