Re[5]: Как защитить mutex singletona
От: andrey.desman  
Дата: 12.04.11 16:48
Оценка: 4 (1)
Здравствуйте, баг, Вы писали:

баг>Не верю.

Счастливой отладки!

баг>Это всё равно, что сказать

баг>
1. std::string* str = new std::string("abc");
баг>2. str->data();
баг>

баг>что в точке 2 str будет указывать на какой-то объект класса std::string, который ещё не сконструирован строкой "abc" из-за переупорядочивания инструкций компилятором/процессором

Не все равно. Здесь очевидная для компилятора зависимость (2) от (1), а там этой зависимости нет, потому что о потоках компилятор ничего не знает. Вообще не все так просто, как кажется на первый взгляд. Ссылку здесь уже приводили, почитай, много интересного узнаешь
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
Re[3]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 10.04.11 14:58
Оценка: 2 (1)
Здравствуйте, brankovic, Вы писали:

B>простите, что немного офтоп, но нельзя ли пояснить, что тут не так? На практике проблем не было (гцц), и я так понимаю гцц это дело поддерживает, но может какие-то там ещё проблемы глубже, очень хотелось бы понять.


Все нормально. По теме сошлюсь на: http://stackoverflow.com/questions/1270927/are-function-static-variables-thread-safe-in-gcc

Но обычно хотят singleton близкий по описанию к singleton с двумя проверками, чтобы под другими компиляторами (MSVC) тоже работало. Ну, и соответственно, пиплы, программирующие исключительно под MSVC, на собеседованиях относятся к варианту от gcc крайне скептически и готовы прямо в митингруме расжечь костер и наказать еретика. Несмотря на то, что старательно объясняешь разницу, они не могут поверить, что компилятор может следить... Доставляет, однако.
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[17]: Как защитить mutex singletona
От: andrey.desman  
Дата: 11.04.11 10:55
Оценка: 2 (1)
Здравствуйте, Kolobrodin, Вы писали:

K>Здравствуйте, andrey.desman, Вы писали:


AD>>Смысл в том, чтобы использовать тип с максимальным выравниванием, тогда любые данные по этому адресу будут выровнены.


K>Я вот это не догнал Выравнивание размера или выравнивание адреса и как оно взаимосвязано?


Для базовых типов выравнивается адрес. Размер дополняется, чтобы этот тип в массиве сохранял свое выравнивание. Например, это делается для long double, который имеет реальный размер 10 байт, но на 32 битах требует выравнивания на 4 байта. Соответственно, его размер добивается до 12 байт, а на 64 битах требует выравнивания 16 байт и размер его дополняется до 16 байт.
Соответственно, выравнивание структуры — это максимальное выравнивание члена этой структуры (рекурсивно и для подструктур/юнионов), и размер структуры дополняется для того, чтобы в массиве выравнивание для каждого члена сохранялось.

Вот кстати, вариант с юнионом наверное лучший long double заставляет компилятор выровнять aligned_data по максимуму.

union sp
{
char spinlock_data[sizeof(spinlock)];
long double align;
} aligned_data;
Re: Как защитить mutex singletona
От: Аноним  
Дата: 06.04.11 08:29
Оценка: -1
Здравствуйте, Аноним, Вы писали:

А>Всем привет.

А>Вопрос по поводу реализации многопоточной защиты патерна singleton, везде описаны средтсва как защитить сам instance от опроса разными тредами, но как быть увереным, что сам объект синхронизации находится в валидном состоянии ?
А>Вот как пример

А>
А>static InstanceTypeRef  getInstance()
А>{
А>    if( NULL == ms_instance )
А>    {
А>        static boost::mutex  instanceMutex;
А>        boost::lock_guard< boost::mutex >  sentinel( instanceMutex );
А>        if( NULL == ms_instance )
А>        {
А>            ms_instance = new InstanceType();
А>        }
А>    }
А>    return  * ms_instance;
А>}
А>

А>Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?

А>спс.


ИМХО проблема вашей реализации в вызове ms_instance = new InstanceType(); Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType. Если в это момент другой поток вызовет getInstance то возможно возвращение не полностью валидного ms_instance. В новом стандарте C++ это решается объявлением ms_instance как volatile.
Как защитить mutex singletona
От: Аноним  
Дата: 06.04.11 05:22
Оценка:
Всем привет.
Вопрос по поводу реализации многопоточной защиты патерна singleton, везде описаны средтсва как защитить сам instance от опроса разными тредами, но как быть увереным, что сам объект синхронизации находится в валидном состоянии ?
Вот как пример

static InstanceTypeRef  getInstance()
{
    if( NULL == ms_instance )
    {
        static boost::mutex  instanceMutex;
        boost::lock_guard< boost::mutex >  sentinel( instanceMutex );
        if( NULL == ms_instance )
        {
            ms_instance = new InstanceType();
        }
    }
    return  * ms_instance;
}

Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?

спс.
Re: Как защитить mutex singletona
От: Caracrist https://1pwd.org/
Дата: 06.04.11 06:47
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Как можно защитится от этого ?

        template <typename T> class Singletone
        {
            static T * m_instance;
            static SIMPLE_MUTEX m_mutex;
            static void CreateInstance()
            {
                SIMPLE_MUTEX::lockT lock_(m_mutex);
                static T loc_instance;
                m_instance = &loc_instance;
            }
        public:
            static T * Instance()
            {
                if (!m_instance)
                    CreateInstance();
                return m_instance;
            };
        }; // class Singletone<T>
        template <typename T> T * Singletone<T>::m_instance = NULL;
        template <typename T> SIMPLE_MUTEX Singletone<T>::m_mutex;

~~~~~
~lol~~
~~~ Single Password Solution
Re[2]: Как защитить mutex singletona
От: баг  
Дата: 06.04.11 08:51
Оценка:
Здравствуйте, Аноним, Вы писали:

A> Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType.

Каким образом?
Re[2]: Как защитить mutex singletona
От: Аноним  
Дата: 06.04.11 18:46
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>Здравствуйте, Аноним, Вы писали:


А>> Как можно защитится от этого ?

C>
C>        template <typename T> class Singletone
C>        {
C>            static T * m_instance;
C>            static SIMPLE_MUTEX m_mutex;
C>            static void CreateInstance()
C>            {
C>                SIMPLE_MUTEX::lockT lock_(m_mutex);
C>                static T loc_instance;
C>                m_instance = &loc_instance;
C>            }
C>        public:
C>            static T * Instance()
C>            {
C>                if (!m_instance)
C>                    CreateInstance();
C>                return m_instance;
C>            };
C>        }; // class Singletone<T>
C>        template <typename T> T * Singletone<T>::m_instance = NULL;
C>        template <typename T> SIMPLE_MUTEX Singletone<T>::m_mutex;
C>

C>

В вашей ситуации все еще хуже, сначала могут быть обращения к CreateInstance а потом только инициализация
template <typename T> SIMPLE_MUTEX Singletone<T>::m_mutex; Помимо оставшейся ситуации, когда объект был создан раньше template <typename T> SIMPLE_MUTEX Singletone<T>::m_mutex , и имеет возможность дернуть метод уже после разрушения m_mutex. Не говоря уже о том, что создание статической переменной не гаранировано ПОСЛЕ захвата мутекса, она же статическая, я так понимаю компилятор спокойно сможет начать строить ее при первом обращении к функции, а потом туда влезет другой поток... и что тогда ?
Re: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 08.04.11 21:44
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?


Долго вчитывался, так и не понял, что конкретно имелось ввиду

У вас instanceMutex объявлен static. Поменяли шило на мыло.
С таким же успехом можно было заюзать:

static InstanceTypeRef getInstance()
{
static InstanceType s_instance;
return s_instance;
}

И надо сказать, это кое-где работает

Другие варианты:
1) сделать мьютекс статическим членом класса, но при этом нужна гарантия, что до входа в main() getInstance() вызываться не будет (второй Аноним уже намекнул на это);
2) использовать счетчики Шварца, если нужно дергать getInstance() когда угодно.

Отвечая второму Анониму (предположу, что звать Олегом? ) :

Здравствуйте, Аноним, Вы писали:

А>ИМХО проблема вашей реализации в вызове ms_instance = new InstanceType(); Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType. Если в это момент другой поток вызовет getInstance то возможно возвращение не полностью валидного ms_instance. В новом стандарте C++ это решается объявлением ms_instance как volatile.


Что касается указанной проблемы синглтона. Если не использовать новый стандарт, тогда вариантов немного: использовать временную переменную, а потом самопальными мембарами и compare_and_swap с ms_instanse.
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[2]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 08.04.11 22:04
Оценка:
Вот здесь
Автор: d.4
Дата: 25.02.11
ранее обсуждалось, заодно и статья Майерса и Александреску о проблеме здесь
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[3]: Как защитить mutex singletona
От: andrey.desman  
Дата: 09.04.11 09:35
Оценка:
Здравствуйте, баг, Вы писали:

баг>Здравствуйте, Аноним, Вы писали:


A>> Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType.

баг>Каким образом?

Это как минимум три разных операции (если смотреть не самый низкий уровень): выделение памяти, вызов конструкторов, запись в переменную. Последние два компилятор/процессор может распараллелить или поменять местами. Временной отрезок очень мал, но он есть. И новый вродебы и правда решает проблему.

Да и в текущем C++ не помешает volatile, так как идет два чтения переменной подряд.
Re[2]: Как защитить mutex singletona
От: Аноним  
Дата: 09.04.11 16:31
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>Здравствуйте, Аноним, Вы писали:


А>>Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?


K>Долго вчитывался, так и не понял, что конкретно имелось ввиду


K>У вас instanceMutex объявлен static. Поменяли шило на мыло.

K>С таким же успехом можно было заюзать:

K>static InstanceTypeRef getInstance()

K>{
K> static InstanceType s_instance;
K> return s_instance;
K>}

K>И надо сказать, это кое-где работает


K>Другие варианты:

K>1) сделать мьютекс статическим членом класса, но при этом нужна гарантия, что до входа в main() getInstance() вызываться не будет (второй Аноним уже намекнул на это);
K>2) использовать счетчики Шварца, если нужно дергать getInstance() когда угодно.

K>Отвечая второму Анониму (предположу, что звать Олегом? ) :


K>Здравствуйте, Аноним, Вы писали:


А>>ИМХО проблема вашей реализации в вызове ms_instance = new InstanceType(); Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType. Если в это момент другой поток вызовет getInstance то возможно возвращение не полностью валидного ms_instance. В новом стандарте C++ это решается объявлением ms_instance как volatile.


K>Что касается указанной проблемы синглтона. Если не использовать новый стандарт, тогда вариантов немного: использовать временную переменную, а потом самопальными мембарами и compare_and_swap с ms_instanse.


О, спс, за внимание, уже не ожидал, что по теме что либо всплывет
Меня зовут, не Олег, незнаю уж, как вы так решили догадатся Федя, очень приятно
K>Долго вчитывался, так и не понял, что конкретно имелось ввиду
Ситуация такая, проблема KDL (keyboard, dysplay, log), как у александреску, тока при многопоточном доступе.
вот пример, на коленке написаный

struct mutex
{
  criticalsection_or_some_other * m;
  ~mutex(){ uninit(m); }              // 1.
  mutex(){ init(m); }                 // 2.
   lock(){ lock(m);}                  // 3.
   unlock(){ unlock(m);}              // 4.
};

struct lock
{
  mutex  & m;
  ~lock(){ m.unlock(); }              // 5.
  lock( mutex & m):m(m){ m.lock(); }  // 6.
};

template< typename T >
class singleton
{
  static T  * volatile ms_instance;
  static mutex ms_instanceMutex;

  public:
    T & getInstance()
    {
      if( NULL == ms_instance )
      {
          lock  sentinel( ms_instanceMutex ); // 7.
          if( NULL == ms_instance )
          {
              ms_instance = new T();
          }
      }
      return  * ms_instance;
    }
};

tempate< typename T >
T * volatile  singleton< T >::ms_instance; // 8.
tempate< typename T >
mutex singleton< T >::ms_mutex;            // 9.




// теперь пошел хаос с файлами проекта, и прочим, где то имеем
#include <logsingleton>
struct Test
{
  Test()
  {
    singleton< log >::getInstance().write( "foo" );
  }
};

struct TestEnter
{
  TestEnter()
  {
    Test  t;
  }
};
struct TestExit
{
  ~TestExit()
  {
    Test  t;
  }
};

testExit g_t1;
// проблема 1
// если конструирование этого объекта начнется раньше, чем 9., то в деструкторе будет вызвано 7. а там будет вызвано 6. а там деинициализированое значение барьера

testEnter g_t2; 
// проблема 2
// если конструирование этого объекта начнется раньше, чем 9., то в конструторе будет вызвано 7. а там будет вызвано 6. а там не инициализированое значение барьера, там только память выделеная под него
// проблема 3
// понять когда instance надо удалить

В общем видно, что проблемы получить instance как таковой не стоит, получить еге легко и просто и если не использовать межпотоковую синхронизацию, то есть только одна проблема, когда прибить синглетон, этот вопрос обмусолен со всех сторон у александреску, так что я его не поднимаю. Остается решить две проблемы, каждая из которых в принципе требует одного и того же, чтобы объект синхронизации был гарантировано сконструирован ДО первого обращения к getInstance. Счетчик шварца насколько я понял, просто будет засорять каждый юнит трансляции еще одним статическим объектом, который непонятно, что будет делать, веть создавать инстанс синглетона от него не требуется, это надо делать только в случае необходимости.

Вот как то так. Если это не проблема, то хотелось бы знать это, если это уже имеет решение, то тоже не отказался бы вкурить пруф. Пока реализовал свою защиту, то она также имеет слабое место.
Re[3]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 17:01
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Федя, очень приятно


Понятно, просто в таком же контексте точно такое же мне не так давно говорил один человек, вот и подумал.

А>В общем видно, что проблемы получить instance как таковой не стоит, получить еге легко и просто и если не использовать межпотоковую синхронизацию, то есть только одна проблема, когда прибить синглетон, этот вопрос обмусолен со всех сторон у александреску, так что я его не поднимаю. Остается решить две проблемы, каждая из которых в принципе требует одного и того же, чтобы объект синхронизации был гарантировано сконструирован ДО первого обращения к getInstance. Счетчик шварца насколько я понял, просто будет засорять каждый юнит трансляции еще одним статическим объектом, который непонятно, что будет делать, веть создавать инстанс синглетона от него не требуется, это надо делать только в случае необходимости.


Здесь проблема в контроле порядка создания статических переменных в разных юнитах, что вообщем-то неопределено, но какими-то трюками либо "волевыми решениями" можно добиться нужного результата. Счетчик шварца не будет создавать инстанс. Он будет создавать мьютекс. И только один.

А>Вот как то так. Если это не проблема, то хотелось бы знать это, если это уже имеет решение, то тоже не отказался бы вкурить пруф. Пока реализовал свою защиту, то она также имеет слабое место.
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[3]: Как защитить mutex singletona
От: Caracrist https://1pwd.org/
Дата: 09.04.11 17:05
Оценка:
Здравствуйте, Аноним, Вы писали:

Named Mutex и его аналоги в других системах...
~~~~~
~lol~~
~~~ Single Password Solution
Re[4]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 17:09
Оценка:
K>Здесь проблема в контроле порядка создания статических переменных в разных юнитах, что вообщем-то неопределено, но какими-то трюками либо "волевыми решениями" можно добиться нужного результата. Счетчик шварца не будет создавать инстанс. Он будет создавать мьютекс. И только один.

Под "волевыми решениями" я подразумеваю что-то типа: собрать все глобальные переменные в одном месте и упорядочить.
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[5]: Как защитить mutex singletona
От: Аноним  
Дата: 09.04.11 18:41
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>>Здесь проблема в контроле порядка создания статических переменных в разных юнитах, что вообщем-то неопределено, но какими-то трюками либо "волевыми решениями" можно добиться нужного результата. Счетчик шварца не будет создавать инстанс. Он будет создавать мьютекс. И только один.


K>Под "волевыми решениями" я подразумеваю что-то типа: собрать все глобальные переменные в одном месте и упорядочить.


Я не много не понял, как будет работать счетчик шварца в конкретной задаче ? если он будет просто инициализировать мутекс при необходимости в каждой единице трансляции, то в этом нету смысла. Если есть другой тайный смысл, я бы его выслушал Сейчас делаю аналогично, подобному поведению, тока на мой взгляд более элегантно, использую синглетон Мейерса для создания прокси объекта указателя на инстанс и защищающий его мутекс, таким образом и сам инстанс и защищающий его мутекс повязаны вместе, нету возможности добратся до экземпляра без инициализации мутекса любому другому объекту даже глобальному. Так же решается проблема очередности, возможностью взятия адреса этого хранилища, что приведет к форсированию его создания, без создания инстанса. Что перекрывает все дыры, непонимаю, почему у александресу так сложно все было придумано через Lifetime, когда можно было просто гарантировано пропихнуть на стек более важный объект. Осталась тока одна дыра, которую вообще не представляю как решать ибо она какая то циклическая — это инициализация самого мутекса, если форсировать задержку через Sleep и долбится сразу другими потоками, то вроде прошибается. Просто если сделать еще одну обрамляющую секцию инициализации, то ее опять таки надо лочить статическим мутексом, и опять приходим к тому, что если не успеваем в первом потоке завершить полное создание муткса, то можем получить fail.
Эх, иметь бы некий 100% сконструированный объект синхронизации.
Re[6]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 18:51
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я не много не понял, как будет работать счетчик шварца в конкретной задаче ? если он будет просто инициализировать мутекс при необходимости в каждой единице трансляции, то в этом нету смысла.


Вот тут подробнее: тыц
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[7]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 19:07
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>Здравствуйте, Аноним, Вы писали:


Вот примерчик, выдрал из проекта:

.hpp:


size_t make_index();

// Nifty (Schwarz) counter.
static struct spec_ptr_initializer
{
    // Init here.
    spec_ptr_initializer();

    // Clean-up here.
    ~spec_ptr_initializer();

    static size_t s_nifty_counter;

} spec_ptr_init;                                            // spec_ptr_initializer




.cpp:



namespace {

size_t g_ptr_index;

static char spinlock_data[sizeof(spinlock)];                
spinlock* ptr = reinterpret_cast<spinlock*>(&spinlock_data);// NOTE: if make reinterpret_cast from
spinlock& g_spinlock = static_cast<spinlock&>(*ptr);        // char* to spinlock& then will be warning
                                                            // [dereferencing type-punned pointer will
                                                            // break strict-aliasing rules]

}                                                           // unnamed namespace

size_t make_index()
{
    scoped_lock<spinlock> lock(&g_spinlock);
    return g_ptr_index++;
}

// Nifty counter.
size_t spec_ptr_initializer::s_nifty_counter;

// Nifty counter init.
spec_ptr_initializer::spec_ptr_initializer()
{
    if (0 == s_nifty_counter++)
    {
        new (&spinlock_data) spinlock();
        printf("%s", "Create spinlock\n");
    }
}

// Nifty counter clean-up.
spec_ptr_initializer::~spec_ptr_initializer()
{
    if (0 == --s_nifty_counter)
    {
        (&g_spinlock)->~spinlock();
        printf("%s", "Destroy spinlock\n");
    }
}
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[8]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 19:15
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>Здравствуйте, Kolobrodin, Вы писали:


K>>Здравствуйте, Аноним, Вы писали:


K>Вот примерчик, выдрал из проекта:


K>.hpp:



K>
K>size_t make_index();

K>// Nifty (Schwarz) counter.
K>static struct spec_ptr_initializer
K>{
K>    // Init here.
K>    spec_ptr_initializer();

K>    // Clean-up here.
K>    ~spec_ptr_initializer();

K>    static size_t s_nifty_counter;

K>} spec_ptr_init;                                            // spec_ptr_initializer
K>




K>.cpp:



K>

K>namespace {

K>size_t g_ptr_index;

K>static char spinlock_data[sizeof(spinlock)];                
K>spinlock* ptr = reinterpret_cast<spinlock*>(&spinlock_data);// NOTE: if make reinterpret_cast from
K>spinlock& g_spinlock = static_cast<spinlock&>(*ptr);        // char* to spinlock& then will be warning
K>                                                            // [dereferencing type-punned pointer will
K>                                                            // break strict-aliasing rules]

K>}                                                           // unnamed namespace

K>size_t make_index()
K>{
K>    scoped_lock<spinlock> lock(&g_spinlock);
K>    return g_ptr_index++;
K>}

K>// Nifty counter.
K>size_t spec_ptr_initializer::s_nifty_counter;

K>// Nifty counter init.
K>spec_ptr_initializer::spec_ptr_initializer()
K>{
K>    if (0 == s_nifty_counter++)
K>    {
K>        new (&spinlock_data) spinlock();
K>        printf("%s", "Create spinlock\n");
K>    }
K>}

K>// Nifty counter clean-up.
K>spec_ptr_initializer::~spec_ptr_initializer()
K>{
K>    if (0 == --s_nifty_counter)
K>    {
K>        (&g_spinlock)->~spinlock();
K>        printf("%s", "Destroy spinlock\n");
K>    }
K>}

K>


Таким образом, make_index() можно использовать в других статических объектах.
Как сказано тут эта техника применяется для создания std::cout, std::cin, std::cerr, std::clog. Поэтому cout мы можем использовать в конструкторах глобальных объектов.
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[9]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 19:24
Оценка:
Небольшой фикс:

.hpp


// Nifty (Schwarz) counter.
struct spec_ptr_initializer
{
    // Init here.
    spec_ptr_initializer();

    // Clean-up here.
    ~spec_ptr_initializer();

};                                                                              // spec_ptr_initializer

namespace {

spec_ptr_initializer s_spec_ptr_init;                                           // spec_ptr_initializer

}

// unnamed namespace

.cpp


namespace {

size_t s_nifty_counter;                                                         // Nifty counter.

size_t g_ptr_index;

static char spinlock_data[sizeof(spinlock)];                                    
spinlock* ptr = reinterpret_cast<spinlock*>(&spinlock_data);                    // NOTE: if make reinterpret_cast from
spinlock& g_spinlock = static_cast<spinlock&>(*ptr);                            // char* to spinlock& then will be warning
                                                                                // [dereferencing type-punned pointer will
                                                                                // break strict-aliasing rules]

}
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[10]: Как защитить mutex singletona
От: Аноним  
Дата: 09.04.11 22:58
Оценка:
>Здравствуйте, Kolobrodin, Вы писали:
>...

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

Recommendation: Don't create threads during global object initialization.



А создание у вас глобального спин лока, понравилась, я так понял, что в каждом юните появится этот инициализатор, а так как инклюды обычно выше пишут, чем код, то он встанет в стек раньше, и проживет соответсвенно дольше , только не понял, почему его в статической памяти так усердно (многострочно) пытались разместить. И опять таки, нету гарантий, что scoped_lock<spinlock> lock(&g_spinlock); вызовется позже чем будет полный init. Кроме соответсвующий конвенции не вызывать потоки из конструкторов глобальных объектов

А еще зацепил кусок кода

Local &GetLocal()
{
  static int              guard; // Will be zeroed at load time
  spin_mutex              smx(&guard); // Spin on "guard"
  lock_scope<spin_mutex>  lock(smx);   // Scope lock of "smx"
  static Local            local;
  return local;
}


который как раз у меня такой же, я все хотел как то зацепить выход из функции глобальным mutex но никак не вкурю как это, и тут вроде написано, как раз тоже самое, но что это за мутекс такой ? самопальный ? У Рихтера есть пример как сделать собственный spinlock на базе интрелокед функций, но имхо, это не тот случай, чтобы огород городить, если бы был "стандартный" то это было бы супер
Re[11]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 09.04.11 23:51
Оценка:
Здравствуйте, Аноним, Вы писали:

>>Здравствуйте, Kolobrodin, Вы писали:

>>...

А>О, спс, за ссылку, как раз рассматриваются те вопросы что меня мучают

А>Вынес, походу одну самую важную вещь

А>

А>Recommendation: Don't create threads during global object initialization.

А>

Одна из самых важных рекомендаций.

А>А создание у вас глобального спин лока, понравилась, я так понял, что в каждом юните появится этот инициализатор, а так как инклюды обычно выше пишут, чем код, то он встанет в стек раньше, и проживет соответсвенно дольше , только не понял, почему его в статической памяти так усердно (многострочно) пытались разместить. И опять таки, нету гарантий, что scoped_lock<spinlock> lock(&g_spinlock); вызовется позже чем будет полный init. Кроме соответсвующий конвенции не вызывать потоки из конструкторов глобальных объектов


В догонку по теме : здесь С объяснением нюансов.

А>А еще зацепил кусок кода


А>
А>Local &GetLocal()
А>{
А>  static int              guard; // Will be zeroed at load time
А>  spin_mutex              smx(&guard); // Spin on "guard"
А>  lock_scope<spin_mutex>  lock(smx);   // Scope lock of "smx"
А>  static Local            local;
А>  return local;
А>}
А>


А>который как раз у меня такой же, я все хотел как то зацепить выход из функции глобальным mutex но никак не вкурю как это, и тут вроде написано, как раз тоже самое, но что это за мутекс такой ? самопальный ? У Рихтера есть пример как сделать собственный spinlock на базе интрелокед функций, но имхо, это не тот случай, чтобы огород городить, если бы был "стандартный" то это было бы супер


Может здесь или здесь?
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[10]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 10.04.11 00:11
Оценка:
K>
K>namespace {

K>size_t s_nifty_counter;                                                         // Nifty counter.

K>size_t g_ptr_index;

K>static char spinlock_data[sizeof(spinlock)];                                    
K>spinlock* ptr = reinterpret_cast<spinlock*>(&spinlock_data);                    // NOTE: if make reinterpret_cast from
K>spinlock& g_spinlock = static_cast<spinlock&>(*ptr);                            // char* to spinlock& then will be warning
K>                                                                                // [dereferencing type-punned pointer will
K>                                                                                // break strict-aliasing rules]

K>}
K>


Надо чаще на старый код смотреть. Зачем-то static в namespace засунул
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[2]: Как защитить mutex singletona
От: brankovic  
Дата: 10.04.11 13:20
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>С таким же успехом можно было заюзать:


K>static InstanceTypeRef getInstance()

K>{
K> static InstanceType s_instance;
K> return s_instance;
K>}

K>И надо сказать, это кое-где работает


простите, что немного офтоп, но нельзя ли пояснить, что тут не так? На практике проблем не было (гцц), и я так понимаю гцц это дело поддерживает, но может какие-то там ещё проблемы глубже, очень хотелось бы понять.
Re[4]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 10.04.11 15:28
Оценка:
K>Но обычно хотят singleton близкий по описанию к singleton с двумя проверками, чтобы под другими компиляторами (MSVC) тоже работало. Ну, и соответственно, пиплы, программирующие исключительно под MSVC, на собеседованиях относятся к варианту от gcc крайне скептически и готовы прямо в митингруме расжечь костер и наказать еретика. Несмотря на то, что старательно объясняешь разницу, они не могут поверить, что компилятор может следить... Доставляет, однако.

Ни в коем случае не стоит рассматривать фразу как приглашение к холивару, но как предостережение от холивара
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[12]: Как защитить mutex singletona
От: Аноним  
Дата: 10.04.11 17:06
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>Может здесь или здесь?

конкуренция со спином хорошо конечно, но надо же конкурировать за ИНИЦИАЛИЗИРОВАННЫЙ объект, тоесть создать статик синхронизатор, а потом его лочить. И тем самым возвращаемся к проблеме лока во время инициализации статики Или я чего не понял ? Можно создать шаблоный статик для класса и после входа в main можно гарантировано лочится им в любых классах. Но это не то, это другие задачи решает, уже просто синхронизацию, а тут основная трабла защитится от дыр при построение глобальной статики. Даже если мы втыкиваем инициалиацию этого синхронизатора через шварца, то в самом шварце защиты тоже нету.
О, gcc поддерживает thread-safe инициализацию, вот блин молодцы.

PS >Надо чаще на старый код смотреть. Зачем-то static в namespace засунул
Красоту наводишь ? каждая переменная имеет linkage spec, по умолчанию static, все равно что signed перед int написать
Re[11]: Как защитить mutex singletona
От: andrey.desman  
Дата: 10.04.11 17:45
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>Надо чаще на старый код смотреть. Зачем-то static в namespace засунул


Раз уж на то пошло, то можно еще и spinlock_data выровнять.
Re[12]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 10.04.11 19:28
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Здравствуйте, Kolobrodin, Вы писали:


K>>Надо чаще на старый код смотреть. Зачем-то static в namespace засунул


AD>Раз уж на то пошло, то можно еще и spinlock_data выровнять.


Спасибо А как это лучше сделать инновационным способом?

ЗЫ. Как там в Индусии?
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[13]: Как защитить mutex singletona
От: andrey.desman  
Дата: 11.04.11 09:23
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

AD>>Раз уж на то пошло, то можно еще и spinlock_data выровнять.

K>Спасибо А как это лучше сделать инновационным способом?

А х.з.
Можно так:
static int spinlock_data_int[(sizeof(spinlock) + sizeof(int) - 1) / sizeof(int)];
static char *spinlock_data = reinterpret_cast<char *>(spinlock_data_int);


Или так:
struct sdata
{
int dummy;
char data[sizeof(spinlock)];
} spinlock_data;


Но здесь теоритических гарантий на выравнивание нет, хотя на практике ни один из компиляторов не будет мусорить дырками между dummy и data.

Как-то сталкивался с такой проблемой, когда портировал код на более старый армовский компилятор. Там std::wstring вылетал в конструкторе по умолчанию из-за невыровненных данных. Да, там тоже выделяли память статик чаром под единый инстанс пустой строки Задолбался я тогда ковыряться в недрах того STL, продираясь сквозь все эти жутко нечитаемые шаблоны в шаблонах и #ifdef.

K>ЗЫ. Как там в Индусии?

Дурдом там Пришел к выводу, что все это нужно только чтобы увидеть красивую картинку перед смертью
Re[14]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 11.04.11 09:38
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Здравствуйте, Kolobrodin, Вы писали:


AD>>>Раз уж на то пошло, то можно еще и spinlock_data выровнять.

K>>Спасибо А как это лучше сделать инновационным способом?

AD>А х.з.

AD>Можно так:
AD>
AD>static int spinlock_data_int[(sizeof(spinlock) + sizeof(int) - 1) / sizeof(int)];
AD>static char *spinlock_data = reinterpret_cast<char *>(spinlock_data_int);
AD>


AD>Или так:

AD>
AD>struct sdata
AD>{
AD>int dummy;
AD>char data[sizeof(spinlock)];
AD>} spinlock_data;
AD>


AD>Но здесь теоритических гарантий на выравнивание нет, хотя на практике ни один из компиляторов не будет мусорить дырками между dummy и data.


AD>Как-то сталкивался с такой проблемой, когда портировал код на более старый армовский компилятор. Там std::wstring вылетал в конструкторе по умолчанию из-за невыровненных данных. Да, там тоже выделяли память статик чаром под единый инстанс пустой строки Задолбался я тогда ковыряться в недрах того STL, продираясь сквозь все эти жутко нечитаемые шаблоны в шаблонах и #ifdef.


std::aligned_storage в <type_traits> есть. Это из нового С++0х.

Объявлено так:

  template<std::size_t _Len, std::size_t _Align>
    struct aligned_storage
    { 
      union type
      {
    unsigned char __data[_Len];
    struct __attribute__((__aligned__((_Align)))) { } __align; 
      };
    };


Предположение, что данные, кратные по размеру некоторому X, компилятор пытается разместить по кратному X адресу? Иначе смысла не вижу.


K>>ЗЫ. Как там в Индусии?

AD>Дурдом там Пришел к выводу, что все это нужно только чтобы увидеть красивую картинку перед смертью
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[15]: Как защитить mutex singletona
От: andrey.desman  
Дата: 11.04.11 10:28
Оценка:
Здравствуйте, Kolobrodin, Вы писали:

K>Предположение, что данные, кратные по размеру некоторому X, компилятор пытается разместить по кратному X адресу? Иначе смысла не вижу.


Пытается? Нечеткая логика, ха.

У разных базовых типов разное выравнивание на разных платформах и даже компиляторах. И компилятор обязан это выравнивание соблюсти, если не сказано иначе (типа packed, __align__ и т.д.).
Смысл в том, чтобы использовать тип с максимальным выравниванием, тогда любые данные по этому адресу будут выровнены.
Максимальное выравнивание, которое мне известно, имеет long double на 64-битном линуксе (16 байт), так что тут int ничего не решает, если внутри spinlock есть long double
Re[16]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 11.04.11 10:35
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Смысл в том, чтобы использовать тип с максимальным выравниванием, тогда любые данные по этому адресу будут выровнены.


Я вот это не догнал Выравнивание размера или выравнивание адреса и как оно взаимосвязано?
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[18]: Как защитить mutex singletona
От: Kolobrodin Россия  
Дата: 11.04.11 11:16
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Здравствуйте, Kolobrodin, Вы писали:


K>>Здравствуйте, andrey.desman, Вы писали:


AD>>>Смысл в том, чтобы использовать тип с максимальным выравниванием, тогда любые данные по этому адресу будут выровнены.


K>>Я вот это не догнал Выравнивание размера или выравнивание адреса и как оно взаимосвязано?


AD>Для базовых типов выравнивается адрес. Размер дополняется, чтобы этот тип в массиве сохранял свое выравнивание. Например, это делается для long double, который имеет реальный размер 10 байт, но на 32 битах требует выравнивания на 4 байта. Соответственно, его размер добивается до 12 байт, а на 64 битах требует выравнивания 16 байт и размер его дополняется до 16 байт.

AD>Соответственно, выравнивание структуры — это максимальное выравнивание члена этой структуры (рекурсивно и для подструктур/юнионов), и размер структуры дополняется для того, чтобы в массиве выравнивание для каждого члена сохранялось.

AD>Вот кстати, вариант с юнионом наверное лучший long double заставляет компилятор выровнять aligned_data по максимуму.


AD>
AD>union sp
AD>{
AD>char spinlock_data[sizeof(spinlock)];
AD>long double align;
AD>} aligned_data;
AD>


Понятно
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[4]: Как защитить mutex singletona
От: баг  
Дата: 12.04.11 16:06
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Это как минимум три разных операции (если смотреть не самый низкий уровень): выделение памяти, вызов конструкторов, запись в переменную. Последние два компилятор/процессор может распараллелить или поменять местами.


Вы хотите сказать, что

        boost::lock_guard< boost::mutex >  sentinel( instanceMutex );
        if( NULL == ms_instance )
        {
            ms_instance = new InstanceType();
        }
Может выполниться как
push sizeof(InstanceType)
call operator__new           // => malloc
mov  [ms_instance], eax
push eax
call InstanceType::InstanceType // ctor


Не верю.

Это всё равно, что сказать
1. std::string* str = new std::string("abc");
2. str->data();

что в точке 2 str будет указывать на какой-то объект класса std::string, который ещё не сконструирован строкой "abc" из-за переупорядочивания инструкций компилятором/процессором
Re[5]: Как защитить mutex singletona
От: Аноним  
Дата: 13.04.11 17:07
Оценка:
Здравствуйте, баг, Вы писали:

баг>Здравствуйте, andrey.desman, Вы писали:


AD>>Это как минимум три разных операции (если смотреть не самый низкий уровень): выделение памяти, вызов конструкторов, запись в переменную. Последние два компилятор/процессор может распараллелить или поменять местами.


баг> Вы хотите сказать, что


баг>
        boost::lock_guard< boost::mutex >  sentinel( instanceMutex );
баг>        if( NULL == ms_instance )
баг>        {
баг>            ms_instance = new InstanceType();
баг>        }
баг>
Может выполниться как

баг>
баг>push sizeof(InstanceType)
баг>call operator__new           // => malloc
баг>mov  [ms_instance], eax
баг>push eax
баг>call InstanceType::InstanceType // ctor
баг>


баг>Не верю.

вы не поняли смысл вопроса, поэтому дискусия была продолжена в другой ветке. Дело в том, что в примере

boost::lock_guard< boost::mutex >  sentinel( instanceMutex );

мутекс статический! соответсвенно первый поток может войти и инициировать его конструктор, а второй, зайдя будет подразумевать, что мутекс создан, и в точке захвата будет undefined behavior, если первый не успеет его инициализировать. Если вам это интересно, то в другой(более длинной) ветке обсуждение этой фичи.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.