Паттерны проектирования: singleton — часть1

Thread-safe Singleton

To fix the problem, you have to synchronize threads during the first creation of the Singleton object.


main.py: Conceptual example

from threading import Lock, Thread


class SingletonMeta(type):
    """
    This is a thread-safe implementation of Singleton.
    """

    _instances = {}

    _lock: Lock = Lock()
    """
    We now have a lock object that will be used to synchronize threads during
    first access to the Singleton.
    """

    def __call__(cls, *args, **kwargs):
        """
        Possible changes to the value of the `__init__` argument do not affect
        the returned instance.
        """
        # Now, imagine that the program has just been launched. Since there's no
        # Singleton instance yet, multiple threads can simultaneously pass the
        # previous conditional and reach this point almost at the same time. The
        # first of them will acquire lock and will proceed further, while the
        # rest will wait here.
        with cls._lock:
            # The first thread to acquire the lock, reaches this conditional,
            # goes inside and creates the Singleton instance. Once it leaves the
            # lock block, a thread that might have been waiting for the lock
            # release may then enter this section. But since the Singleton field
            # is already initialized, the thread won't create a new object.
            if cls not in cls._instances:
                instance = super().__call__(*args, **kwargs)
                cls._instances = instance
        return cls._instances


class Singleton(metaclass=SingletonMeta):
    value: str = None
    """
    We'll use this property to prove that our Singleton really works.
    """

    def __init__(self, value: str) -> None:
        self.value = value

    def some_business_logic(self):
        """
        Finally, any singleton should define some business logic, which can be
        executed on its instance.
        """


def test_singleton(value: str) -> None:
    singleton = Singleton(value)
    print(singleton.value)


if __name__ == "__main__":
    # The client code.

    print("If you see the same value, then singleton was reused (yay!)\n"
          "If you see different values, "
          "then 2 singletons were created (booo!!)\n\n"
          "RESULT:\n")

    process1 = Thread(target=test_singleton, args=("FOO",))
    process2 = Thread(target=test_singleton, args=("BAR",))
    process1.start()
    process2.start()

Output.txt: Execution result

If you see the same value, then singleton was reused (yay!)
If you see different values, then 2 singletons were created (booo!!)

RESULT:

FOO
FOO

Thread-safe Singleton

To fix the problem, you have to synchronize threads during the first creation of the Singleton object.

Program.cs: Conceptual example

using System;
using System.Threading;

namespace Singleton
{
    // This Singleton implementation is called "double check lock". It is safe
    // in multithreaded environment and provides lazy initialization for the
    // Singleton object.
    class Singleton
    {
        private Singleton() { }

        private static Singleton _instance;

        // We now have a lock object that will be used to synchronize threads
        // during first access to the Singleton.
        private static readonly object _lock = new object();

        public static Singleton GetInstance(string value)
        {
            // This conditional is needed to prevent threads stumbling over the
            // lock once the instance is ready.
            if (_instance == null)
            {
                // Now, imagine that the program has just been launched. Since
                // there's no Singleton instance yet, multiple threads can
                // simultaneously pass the previous conditional and reach this
                // point almost at the same time. The first of them will acquire
                // lock and will proceed further, while the rest will wait here.
                lock (_lock)
                {
                    // The first thread to acquire the lock, reaches this
                    // conditional, goes inside and creates the Singleton
                    // instance. Once it leaves the lock block, a thread that
                    // might have been waiting for the lock release may then
                    // enter this section. But since the Singleton field is
                    // already initialized, the thread won't create a new
                    // object.
                    if (_instance == null)
                    {
                        _instance = new Singleton();
                        _instance.Value = value;
                    }
                }
            }
            return _instance;
        }

        // We'll use this property to prove that our Singleton really works.
        public string Value { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // The client code.
            
            Console.WriteLine(
                "{0}\n{1}\n\n{2}\n",
                "If you see the same value, then singleton was reused (yay!)",
                "If you see different values, then 2 singletons were created (booo!!)",
                "RESULT:"
            );
            
            Thread process1 = new Thread(() =>
            {
                TestSingleton("FOO");
            });
            Thread process2 = new Thread(() =>
            {
                TestSingleton("BAR");
            });
            
            process1.Start();
            process2.Start();
            
            process1.Join();
            process2.Join();
        }
        
        public static void TestSingleton(string value)
        {
            Singleton singleton = Singleton.GetInstance(value);
            Console.WriteLine(singleton.Value);
        } 
    }
}

Output.txt: Execution result

Концептуальний приклад

Цей приклад показує структуру патерна Одинак, а саме — з яких класів він складається, які ролі ці класи виконують і як вони взаємодіють один з одним.

Після ознайомлення зі структурою, вам буде легше сприймати наступний приклад, що розглядає реальний випадок використання патерна в світі PHP.

index.php: Приклад структури патерна

<?php

namespace RefactoringGuru\Singleton\Conceptual;

/**
 * The Singleton class defines the `GetInstance` method that serves as an
 * alternative to constructor and lets clients access the same instance of this
 * class over and over.
 */
class Singleton
{
    /**
     * The Singleton's instance is stored in a static field. This field is an
     * array, because we'll allow our Singleton to have subclasses. Each item in
     * this array will be an instance of a specific Singleton's subclass. You'll
     * see how this works in a moment.
     */
    private static $instances = [];

    /**
     * The Singleton's constructor should always be private to prevent direct
     * construction calls with the `new` operator.
     */
    protected function __construct() { }

    /**
     * Singletons should not be cloneable.
     */
    protected function __clone() { }

    /**
     * Singletons should not be restorable from strings.
     */
    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize a singleton.");
    }

    /**
     * This is the static method that controls the access to the singleton
     * instance. On the first run, it creates a singleton object and places it
     * into the static field. On subsequent runs, it returns the client existing
     * object stored in the static field.
     *
     * This implementation lets you subclass the Singleton class while keeping
     * just one instance of each subclass around.
     */
    public static function getInstance(): Singleton
    {
        $cls = static::class;
        if (!isset(self::$instances)) {
            self::$instances = new static();
        }

        return self::$instances;
    }

    /**
     * Finally, any singleton should define some business logic, which can be
     * executed on its instance.
     */
    public function someBusinessLogic()
    {
        // ...
    }
}

/**
 * The client code.
 */
function clientCode()
{
    $s1 = Singleton::getInstance();
    $s2 = Singleton::getInstance();
    if ($s1 === $s2) {
        echo "Singleton works, both variables contain the same instance.";
    } else {
        echo "Singleton failed, variables contain different instances.";
    }
}

clientCode();

Output.txt: Результат виконання

Обзор

Внедрение зависимостей (Dependency Injection DI) — это метод разработки программного обеспечения для определения зависимостей между объектами. По сути, это процесс предоставления ресурса, который требуется фрагменту кода. Требуемый ресурс называется зависимостью.При написании кода создаются различные классы и объекты . В большинстве случаев, чтобы выполнять свое предназначение эти классы зависят друг от друга. Классы, или лучший термин «Компоненты», определяют, какие ресурсы им нужны и как их получить. DI управляет определением этих зависимых ресурсов и предоставляет способы их создания. Для реализации этого поведения используется «Контейнер зависимостей (Dependency Container)«. Он создает карту зависимостей для компонентов.Так например, если объект A зависит от объекта B, объект A не должен напрямую импортировать объект B. Вместо этого объект A должен обеспечивать способ внедрения объекта B. Ответственность за создание объекта и внедрение зависимостей должно делегироваться внешнему коду.

Пример Singletone на PHP

<?php
class Singleton
{
    private static $instance = null;

    public static function getInstance()
    {
        
        if (null === self::$instance) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    protected function __construct()
    {
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }
}

class SingletonChild extends Singleton
{
}

$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)

$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance());      // bool(false)

var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)

Код выше реализует паттерн проектирования Singleton с использованием статической переменной, в которой храниться объект и метода getInstance для его создания

Обратите внимание:. 1

конструктор __construct объявлен как protected, чтобы предотвратить создание нового объекта вне класса с помощью оператора new

1. конструктор __construct объявлен как protected, чтобы предотвратить создание нового объекта вне класса с помощью оператора new.

2. магический метод __clone объявлен как private, чтобы предотвратить клонирование объекта с помощью оператора clone.

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

Синглтон можно реализовать с помощью с помощью позднего статического связывания (Начиная с версии PHP 5.3.0).

Чем Singleton НЕ ЯВЛЯЕТСЯ?

  • Singleton — это не метод, а класс.
  • Singleton — это не готовый рецепт создания класса. Есть несколько способов сделать класс синглтоном — мы их рассмотрим далее. Но «начинка» этих классов остается за Вами.

Может ли меняться Singleton?

Да, состояние Singleton-а может быть как изменяемым, так и не изменяемым.

Пример 1 — изменяемый Singleton

Представьте, что у Вас есть сосед Вася. Вася хакер и хочет взломать Вашу почту. Он подбирает пароли — один за другим — и вводит их по очереди.

Именно для защиты от таких Вась и была придумана блокировка. То есть, например, ввел 5 раз неправильно пароль, все — ты заблокирован — и 30 минут не можешь вводить никакие пароли.

А теперь представим, что именно Вам нужно реализовать систему защиты от таких вот Вась на своем сервере.

Обратите внимание, что множественный ввод не так легко отследить как кажется. На Ваш сервер одновременно поступает огромное количество информации


Кроме того, Вася может пытаться вводить пароль с разных IP-адресов, что еще больше усложняет задачу. А нам ведь нужно как-то контролировать количество попыток входа в конкретную учетную запись.

В такой ситуации нам как раз и поможет Singleton!

Каждый раз, когда будет запрашиваться доступ к определенной учетной записи, мы будем перенаправлять этот запрос на некий класс, реализующий паттерн Singleton (ведь нам же надо хранить эту информацию только в единственной «точке»). Данный класс будет считать количество неудачных попыток зайти на сайт.

В данном случае наш Singleton будет изменяемым — каждый раз, когда будет осуществляться попытка доступа к нашей учетной записи, переменная, которая считает количество попыток, будет меняться.

Так, чтобы решить эту проблему, нам понадобился изменяемый Singleton.

Пример 2 — неизменяемый Singleton

Одним из примеров неизменяемого Singleton-а может быть класс, который ставит водяной знак (watermark) на изображения, чтобы предотвратить их кражу.

В принципе, поставить вотермарку на изображение — задача достаточно простая. Классу нужно только получить изображение и отдать уже отредактированную картинку. Если водяной знак будет один и тот же на всех изображениях, тогда нет необходимости менять что-либо и в состоянии класса, поэтому он будет неизменяемым. С этой задачей сможет справиться один экземпляр этого класса,  а значит можем создать класс на основе паттерна Singleton, который будет выполнять одну и ту же задачу — ставить водяные знаки на изображения.

Несмотря на то, что паттерн Singleton может показаться легким в теории, на практике можно наткнуться на «подводные камни». Давайте посмотрим на примерах.

Пример 4 — Хитрая реализация с внутренним классом

public class Singleton {

private Singleton(){…} private static class SingletonHolder { public static final Singleton HOLDER_INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.HOLDER_INSTANCE; } }

1 2 3 4 5 6 7 8 9 10 11 12

publicclassSingleton{

privateSingleton(){…}

privatestaticclassSingletonHolder{

publicstaticfinalSingleton HOLDER_INSTANCE=newSingleton();

}

publicstaticSingleton getInstance(){

returnSingletonHolder.HOLDER_INSTANCE;

}

}

Давайте попробуем реализовать его и запустить.

Реализация


Напишем такой класс:

public class MySingleton {

private MySingleton() { System.out.println(«Singleton created!»); }

private static class SingletonHolder { public static final MySingleton HOLDER_INSTANCE = new MySingleton(); }

public static MySingleton getInstance() { return SingletonHolder.HOLDER_INSTANCE; } }

1 2 3 4 5 6 7 8 9 10 11 12 13 14

publicclassMySingleton{

privateMySingleton(){

System.out.println(«Singleton created!»);

}

privatestaticclassSingletonHolder{

publicstaticfinalMySingleton HOLDER_INSTANCE=newMySingleton();

}

publicstaticMySingleton getInstance(){

returnSingletonHolder.HOLDER_INSTANCE;

}

}

Запустим его с помощью следующего кода:

public class Test { public static void main(String[] args) {

MySingleton firstInstance = MySingleton.getInstance();

System.out.println(firstInstance.getClass());

MySingleton secondInstance = MySingleton.getInstance();

} }

1 2 3 4 5 6 7 8 9 10 11

publicclassTest{

publicstaticvoidmain(Stringargs){

MySingleton firstInstance=MySingleton.getInstance();

System.out.println(firstInstance.getClass());

MySingleton secondInstance=MySingleton.getInstance();

}

}


Получаем:

Комментарии к коду:

Как видите, код в этом примере и в прошлом почти идентичный. Единственная разница — в реализации через внутренний класс.

В чем особенность внутреннего класса? Он позволяет нам, опять же, осуществить ленивую реализацию благодаря особенностям самой Джавы. Дело в том, что внутренние классы загружаются только тогда, когда мы обращаемся к ним впервые — в отличии от «внешних» классов, которые загружаются сразу при запуске программы.

Более того, она потокобезопасна — за счет той же особенности. Почему? Есть такая проблема — если несколько потоков одновременно «стучатся» к одному и тому же объекту, один из них может получить недогруженный объект. Но тут такого нет — благодаря особенностям загрузки внутренних классов

Життєвий приклад

index.php: Приклад з реального світу

<?php

namespace RefactoringGuru\Singleton\RealWorld;

/**
 * If you need to support several types of Singletons in your app, you can
 * define the basic features of the Singleton in a base class, while moving the
 * actual business logic (like logging) to subclasses.
 */
class Singleton
{
    /**
     * The actual singleton's instance almost always resides inside a static
     * field. In this case, the static field is an array, where each subclass of
     * the Singleton stores its own instance.
     */
    private static $instances = [];

    /**
     * Singleton's constructor should not be public. However, it can't be
     * private either if we want to allow subclassing.
     */
    protected function __construct() { }

    /**
     * Cloning and unserialization are not permitted for singletons.
     */
    protected function __clone() { }

    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize singleton");
    }

    /**
     * The method you use to get the Singleton's instance.
     */
    public static function getInstance()
    {
        $subclass = static::class;
        if (!isset(self::$instances)) {
            // Note that here we use the "static" keyword instead of the actual
            // class name. In this context, the "static" keyword means "the name
            // of the current class". That detail is important because when the
            // method is called on the subclass, we want an instance of that
            // subclass to be created here.

            self::$instances = new static();
        }
        return self::$instances;
    }
}

/**
 * The logging class is the most known and praised use of the Singleton pattern.
 * In most cases, you need a single logging object that writes to a single log
 * file (control over shared resource). You also need a convenient way to access
 * that instance from any context of your app (global access point).
 */
class Logger extends Singleton
{
    /**
     * A file pointer resource of the log file.
     */
    private $fileHandle;

    /**
     * Since the Singleton's constructor is called only once, just a single file
     * resource is opened at all times.
     *
     * Note, for the sake of simplicity, we open the console stream instead of
     * the actual file here.
     */
    protected function __construct()
    {
        $this->fileHandle = fopen('php://stdout', 'w');
    }

    /**
     * Write a log entry to the opened file resource.
     */
    public function writeLog(string $message): void
    {
        $date = date('Y-m-d');
        fwrite($this->fileHandle, "$date: $message\n");
    }

    /**
     * Just a handy shortcut to reduce the amount of code needed to log messages
     * from the client code.
     */
    public static function log(string $message): void
    {
        $logger = static::getInstance();
        $logger->writeLog($message);
    }
}

/**
 * Applying the Singleton pattern to the configuration storage is also a common
 * practice. Often you need to access application configurations from a lot of
 * different places of the program. Singleton gives you that comfort.
 */
class Config extends Singleton
{
    private $hashmap = [];

    public function getValue(string $key): string
    {
        return $this->hashmap;
    }

    public function setValue(string $key, string $value): void
    {
        $this->hashmap = $value;
    }
}

/**
 * The client code.
 */
Logger::log("Started!");

// Compare values of Logger singleton.
$l1 = Logger::getInstance();
$l2 = Logger::getInstance();
if ($l1 === $l2) {
    Logger::log("Logger has a single instance.");
} else {
    Logger::log("Loggers are different.");
}

// Check how Config singleton saves data...
$config1 = Config::getInstance();
$login = "test_login";
$password = "test_password";
$config1->setValue("login", $login);
$config1->setValue("password", $password);
// ...and restores it.
$config2 = Config::getInstance();
if ($login == $config2->getValue("login") &&
    $password == $config2->getValue("password")
) {
    Logger::log("Config singleton also works fine.");
}

Logger::log("Finished!");

Output.txt: Результат виконання

2018-06-04: Started!
2018-06-04: Logger has a single instance.
2018-06-04: Config singleton also works fine.
2018-06-04: Finished!

Реализация DI в Python

Внедрение зависимостей в Python мало отличается от общей реализации DI. Для этих целей в Python есть библиотека микро фреймворк, который называется dependency_injector. Этот пакет имеет две основные сущности: контейнеры и провайдеры.Провайдеры описывают, как осуществляется доступ к объектам. Контейнеры — это просто набор провайдеров. Наиболее часто используемые типы провайдеров: Singleton, Configuration и Factory.

Пример

class EmailClient(object):
    
    def __init__(self, config):
        self._config = config
        self.connect(self._config)
        
    def connect(self, config):
        # Implement function here
        pass
class EmailReader(object):
    
    def __init__(self, client):
        try:
            self._client = client
        except Exception as e:
            raise e
            
    def read(self):
        # Implement function here
        pass

Теперь, чтобы определить эти выше упомянутые зависимости извне, создайте новый файл containers.py. Импортируйте пакет dependency_injector и классы для использования в DI.

from dependency_injector import providers, containers
from email_client import EmailClient
from email_reader import EmailReader

Добавьте класс Configs в этот файл. Этот класс будет являться контейнером с поставщиком конфигурации, который предоставляет все объекты конфигурации.

class Configs(containers.DeclarativeContainer):
    config = providers.Configuration('config')
    # other configs
class Clients(containers.DeclarativeContainer):
    email_client = providers.Singleton(EmailClient, Configs.config)
    # other clients 
class Readers(containers.DeclarativeContainer):
    email_reader = providers.Factory(EmailReader, client=Clients.email_client)
    # other readers 

В итоге файл containers.py должен выглядеть следующим образом:

from dependency_injector import providers, containers
from email_client import EmailClient
from email_reader import EmailReader

class Configs(containers.DeclarativeContainer):
    config = providers.Configuration('config')
    # other configs
    
class Clients(containers.DeclarativeContainer):
    email_client = providers.Singleton(EmailClient, Configs.config)
    # other clients
    
class Readers(containers.DeclarativeContainer):
    email_reader = providers.Factory(EmailReader, client=Clients.email_client)
    # other readers

Для запуска примера создайте файл main.py со следующим кодом.

from containers import Readers, Clients, Configs

if __name__ == "__main__":
    Configs.config.override({
        "domain_name": "imap.gmail.com",
        "email_address": "YOUR_EMAIL_ADDRESS",
        "password": "YOUR_PASSWORD",
        "mailbox": "INBOX"
    })
    email_reader = Readers.email_reader()
    print email_reader.read()

Для рабочего примера кода, пожалуйста, обратитесь сюда.

Spread the love

Real World Example

The Singleton pattern is notorious for limiting code reuse and complicating unit testing. However, it’s still very useful in some cases. In particular, it’s handy when you need to control some shared resources. For example, a global logging object that has to control the access to a log file. Another good example: a shared runtime configuration storage.

index.php: Real world example

<?php

namespace RefactoringGuru\Singleton\RealWorld;

/**
 * If you need to support several types of Singletons in your app, you can
 * define the basic features of the Singleton in a base class, while moving the
 * actual business logic (like logging) to subclasses.
 */
class Singleton
{
    /**
     * The actual singleton's instance almost always resides inside a static
     * field. In this case, the static field is an array, where each subclass of
     * the Singleton stores its own instance.
     */
    private static $instances = [];

    /**
     * Singleton's constructor should not be public. However, it can't be
     * private either if we want to allow subclassing.
     */
    protected function __construct() { }

    /**
     * Cloning and unserialization are not permitted for singletons.
     */
    protected function __clone() { }

    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize singleton");
    }

    /**
     * The method you use to get the Singleton's instance.
     */
    public static function getInstance()
    {
        $subclass = static::class;
        if (!isset(self::$instances)) {
            // Note that here we use the "static" keyword instead of the actual
            // class name. In this context, the "static" keyword means "the name
            // of the current class". That detail is important because when the
            // method is called on the subclass, we want an instance of that
            // subclass to be created here.

            self::$instances = new static();
        }
        return self::$instances;
    }
}

/**
 * The logging class is the most known and praised use of the Singleton pattern.
 * In most cases, you need a single logging object that writes to a single log
 * file (control over shared resource). You also need a convenient way to access
 * that instance from any context of your app (global access point).
 */
class Logger extends Singleton
{
    /**
     * A file pointer resource of the log file.
     */
    private $fileHandle;

    /**
     * Since the Singleton's constructor is called only once, just a single file
     * resource is opened at all times.
     *
     * Note, for the sake of simplicity, we open the console stream instead of
     * the actual file here.
     */
    protected function __construct()
    {
        $this->fileHandle = fopen('php://stdout', 'w');
    }

    /**
     * Write a log entry to the opened file resource.
     */
    public function writeLog(string $message): void
    {
        $date = date('Y-m-d');
        fwrite($this->fileHandle, "$date: $message\n");
    }

    /**
     * Just a handy shortcut to reduce the amount of code needed to log messages
     * from the client code.
     */
    public static function log(string $message): void
    {
        $logger = static::getInstance();
        $logger->writeLog($message);
    }
}

/**
 * Applying the Singleton pattern to the configuration storage is also a common
 * practice. Often you need to access application configurations from a lot of
 * different places of the program. Singleton gives you that comfort.
 */
class Config extends Singleton
{
    private $hashmap = [];

    public function getValue(string $key): string
    {
        return $this->hashmap;
    }

    public function setValue(string $key, string $value): void
    {
        $this->hashmap = $value;
    }
}

/**
 * The client code.
 */
Logger::log("Started!");

// Compare values of Logger singleton.
$l1 = Logger::getInstance();
$l2 = Logger::getInstance();
if ($l1 === $l2) {
    Logger::log("Logger has a single instance.");
} else {
    Logger::log("Loggers are different.");
}

// Check how Config singleton saves data...
$config1 = Config::getInstance();
$login = "test_login";
$password = "test_password";
$config1->setValue("login", $login);
$config1->setValue("password", $password);
// ...and restores it.
$config2 = Config::getInstance();
if ($login == $config2->getValue("login") &&
    $password == $config2->getValue("password")
) {
    Logger::log("Config singleton also works fine.");
}

Logger::log("Finished!");

Output.txt: Execution result

2018-06-04: Started!
2018-06-04: Logger has a single instance.
2018-06-04: Config singleton also works fine.
2018-06-04: Finished!

Naïve Singleton

It’s pretty easy to implement a sloppy Singleton. You just need to hide the constructor and implement a static creation method.

The same class behaves incorrectly in a multithreaded environment. Multiple threads can call the creation method simultaneously and get several instances of Singleton class.

main.cc: Conceptual example

/**
 * The Singleton class defines the `GetInstance` method that serves as an
 * alternative to constructor and lets clients access the same instance of this
 * class over and over.
 */
class Singleton
{

    /**
     * The Singleton's constructor should always be private to prevent direct
     * construction calls with the `new` operator.
     */

protected:
    Singleton(const std::string value): value_(value)
    {
    }

    static Singleton* singleton_;

    std::string value_;

public:

    /**
     * Singletons should not be cloneable.
     */
    Singleton(Singleton &other) = delete;
    /**
     * Singletons should not be assignable.
     */
    void operator=(const Singleton &) = delete;
    /**
     * This is the static method that controls the access to the singleton
     * instance. On the first run, it creates a singleton object and places it
     * into the static field. On subsequent runs, it returns the client existing
     * object stored in the static field.
     */

    static Singleton *GetInstance(const std::string& value);
    /**
     * Finally, any singleton should define some business logic, which can be
     * executed on its instance.
     */
    void SomeBusinessLogic()
    {
        // ...
    }

    std::string value() const{
        return value_;
    } 
};

Singleton* Singleton::singleton_= nullptr;;

/**
 * Static methods should be defined outside the class.
 */
Singleton *Singleton::GetInstance(const std::string& value)
{
    /**
     * This is a safer way to create an instance. instance = new Singleton is
     * dangeruous in case two instance threads wants to access at the same time
     */
    if(singleton_==nullptr){
        singleton_ = new Singleton(value);
    }
    return singleton_;
}

void ThreadFoo(){
    // Following code emulates slow initialization.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("FOO");
    std::cout << singleton->value() << "\n";
}

void ThreadBar(){
    // Following code emulates slow initialization.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("BAR");
    std::cout << singleton->value() << "\n";
}


int main()
{
    std::cout <<"If you see the same value, then singleton was reused (yay!\n" <<
                "If you see different values, then 2 singletons were created (booo!!)\n\n" <<
                "RESULT:\n";   
    std::thread t1(ThreadFoo);
    std::thread t2(ThreadBar);
    t1.join();
    t2.join();

    return 0;
}

Output.txt: Execution result

Многопоточный Одиночка

Чтобы исправить проблему, требуется синхронизировать потоки при создании объекта-Одиночки.

main.cc: Пример структуры паттерна

/**
 * Класс Одиночка предоставляет метод `GetInstance`, который ведёт себя как
 * альтернативный конструктор и позволяет клиентам получать один и тот же
 * экземпляр класса при каждом вызове.
 */
class Singleton
{

    /**
     * Конструктор Одиночки всегда должен быть скрытым, чтобы предотвратить
     * создание объекта через оператор new.
     */
private:
    static Singleton * pinstance_;
    static std::mutex mutex_;

protected:
    Singleton(const std::string value): value_(value)
    {
    }
    ~Singleton() {}
    std::string value_;

public:
    /**
     * Одиночки не должны быть клонируемыми.
     */
    Singleton(Singleton &other) = delete;
    /**
     * Singletons should not be assignable.
     */
    void operator=(const Singleton &) = delete;
    /**
     * Это статический метод, управляющий доступом к экземпляру одиночки. При
     * первом запуске, он создаёт экземпляр одиночки и помещает его в
     * статическое поле. При последующих запусках, он возвращает клиенту объект,
     * хранящийся в статическом поле.
     */

    static Singleton *GetInstance(const std::string& value);
    /**
     * Наконец, любой одиночка должен содержать некоторую бизнес-логику, которая
     * может быть выполнена на его экземпляре.
     */
    void SomeBusinessLogic()
    {
        // ...
    }
    
    std::string value() const{
        return value_;
    } 
};

/**
 * Static methods should be defined outside the class.
 */

Singleton* Singleton::pinstance_{nullptr};
std::mutex Singleton::mutex_;

/**
 * The first time we call GetInstance we will lock the storage location
 *      and then we make sure again that the variable is null and then we
 *      set the value. RU:
 */
Singleton *Singleton::GetInstance(const std::string& value)
{
    if (pinstance_ == nullptr)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        if (pinstance_ == nullptr)
        {
            pinstance_ = new Singleton(value);
        }
    }
    return pinstance_;
}

void ThreadFoo(){
    // Этот код эмулирует медленную инициализацию.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("FOO");
    std::cout << singleton->value() << "\n";
}

void ThreadBar(){
    // Этот код эмулирует медленную инициализацию.
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    Singleton* singleton = Singleton::GetInstance("BAR");
    std::cout << singleton->value() << "\n";
}

int main()
{   
    std::cout <<"If you see the same value, then singleton was reused (yay!\n" <<
                "If you see different values, then 2 singletons were created (booo!!)\n\n" <<
                "RESULT:\n";   
    std::thread t1(ThreadFoo);
    std::thread t2(ThreadBar);
    t1.join();
    t2.join();
    
    return 0;
}

Output.txt: Результат выполнения

If you see the same value, then singleton was reused (yay!
If you see different values, then 2 singletons were created (booo!!)

RESULT:
FOO
FOO

С этим читают