Всем привет.
Вопрос по поводу реализации многопоточной защиты патерна singleton, везде описаны средтсва как защитить сам instance от опроса разными тредами, но как быть увереным, что сам объект синхронизации находится в валидном состоянии ?
Вот как пример
Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?
Здравствуйте, Аноним, Вы писали:
А>Всем привет. А>Вопрос по поводу реализации многопоточной защиты патерна singleton, везде описаны средтсва как защитить сам instance от опроса разными тредами, но как быть увереным, что сам объект синхронизации находится в валидном состоянии ? А>Вот как пример
А>
А>Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?
А>спс.
ИМХО проблема вашей реализации в вызове ms_instance = new InstanceType(); Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType. Если в это момент другой поток вызовет getInstance то возможно возвращение не полностью валидного ms_instance. В новом стандарте C++ это решается объявлением ms_instance как volatile.
Здравствуйте, Аноним, Вы писали:
A> Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType.
Каким образом?
Re[2]: Как защитить mutex singletona
От:
Аноним
Дата:
06.04.11 18:46
Оценка:
Здравствуйте, Caracrist, Вы писали:
C>Здравствуйте, Аноним, Вы писали:
А>> Как можно защитится от этого ? C>
В вашей ситуации все еще хуже, сначала могут быть обращения к CreateInstance а потом только инициализация
template <typename T> SIMPLE_MUTEX Singletone<T>::m_mutex; Помимо оставшейся ситуации, когда объект был создан раньше template <typename T> SIMPLE_MUTEX Singletone<T>::m_mutex , и имеет возможность дернуть метод уже после разрушения m_mutex. Не говоря уже о том, что создание статической переменной не гаранировано ПОСЛЕ захвата мутекса, она же статическая, я так понимаю компилятор спокойно сможет начать строить ее при первом обращении к функции, а потом туда влезет другой поток... и что тогда ?
Здравствуйте, Аноним, Вы писали:
А>Если какой то объект будет создан раньше того, как будет вызван этот Instance, и в своем, скажем деструкторе дернет этот Instance, то по идее instanceMutex будет уже не валидным Как можно защитится от этого ?
Долго вчитывался, так и не понял, что конкретно имелось ввиду
У вас instanceMutex объявлен static. Поменяли шило на мыло.
С таким же успехом можно было заюзать:
Другие варианты:
1) сделать мьютекс статическим членом класса, но при этом нужна гарантия, что до входа в main() getInstance() вызываться не будет (второй Аноним уже намекнул на это);
2) использовать счетчики Шварца, если нужно дергать getInstance() когда угодно.
Отвечая второму Анониму (предположу, что звать Олегом? ) :
Здравствуйте, Аноним, Вы писали:
А>ИМХО проблема вашей реализации в вызове ms_instance = new InstanceType(); Возможна ситуация когда в ms_instance будет занесено значение ДО ТОГО как выполнятся все конструкторы класса InstanceType. Если в это момент другой поток вызовет getInstance то возможно возвращение не полностью валидного ms_instance. В новом стандарте C++ это решается объявлением ms_instance как volatile.
Что касается указанной проблемы синглтона. Если не использовать новый стандарт, тогда вариантов немного: использовать временную переменную, а потом самопальными мембарами и compare_and_swap с ms_instanse.
Неоконченная мысль всегда казалась Шри Япутре слишком
Здравствуйте, баг, Вы писали:
баг>Здравствуйте, Аноним, Вы писали:
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. Счетчик шварца насколько я понял, просто будет засорять каждый юнит трансляции еще одним статическим объектом, который непонятно, что будет делать, веть создавать инстанс синглетона от него не требуется, это надо делать только в случае необходимости.
Вот как то так. Если это не проблема, то хотелось бы знать это, если это уже имеет решение, то тоже не отказался бы вкурить пруф. Пока реализовал свою защиту, то она также имеет слабое место.
Здравствуйте, Аноним, Вы писали:
А>Федя, очень приятно
Понятно, просто в таком же контексте точно такое же мне не так давно говорил один человек, вот и подумал.
А>В общем видно, что проблемы получить instance как таковой не стоит, получить еге легко и просто и если не использовать межпотоковую синхронизацию, то есть только одна проблема, когда прибить синглетон, этот вопрос обмусолен со всех сторон у александреску, так что я его не поднимаю. Остается решить две проблемы, каждая из которых в принципе требует одного и того же, чтобы объект синхронизации был гарантировано сконструирован ДО первого обращения к getInstance. Счетчик шварца насколько я понял, просто будет засорять каждый юнит трансляции еще одним статическим объектом, который непонятно, что будет делать, веть создавать инстанс синглетона от него не требуется, это надо делать только в случае необходимости.
Здесь проблема в контроле порядка создания статических переменных в разных юнитах, что вообщем-то неопределено, но какими-то трюками либо "волевыми решениями" можно добиться нужного результата. Счетчик шварца не будет создавать инстанс. Он будет создавать мьютекс. И только один.
А>Вот как то так. Если это не проблема, то хотелось бы знать это, если это уже имеет решение, то тоже не отказался бы вкурить пруф. Пока реализовал свою защиту, то она также имеет слабое место.
Неоконченная мысль всегда казалась Шри Япутре слишком
K>Здесь проблема в контроле порядка создания статических переменных в разных юнитах, что вообщем-то неопределено, но какими-то трюками либо "волевыми решениями" можно добиться нужного результата. Счетчик шварца не будет создавать инстанс. Он будет создавать мьютекс. И только один.
Под "волевыми решениями" я подразумеваю что-то типа: собрать все глобальные переменные в одном месте и упорядочить.
Неоконченная мысль всегда казалась Шри Япутре слишком
Re[5]: Как защитить mutex singletona
От:
Аноним
Дата:
09.04.11 18:41
Оценка:
Здравствуйте, Kolobrodin, Вы писали:
K>>Здесь проблема в контроле порядка создания статических переменных в разных юнитах, что вообщем-то неопределено, но какими-то трюками либо "волевыми решениями" можно добиться нужного результата. Счетчик шварца не будет создавать инстанс. Он будет создавать мьютекс. И только один.
K>Под "волевыми решениями" я подразумеваю что-то типа: собрать все глобальные переменные в одном месте и упорядочить.
Я не много не понял, как будет работать счетчик шварца в конкретной задаче ? если он будет просто инициализировать мутекс при необходимости в каждой единице трансляции, то в этом нету смысла. Если есть другой тайный смысл, я бы его выслушал Сейчас делаю аналогично, подобному поведению, тока на мой взгляд более элегантно, использую синглетон Мейерса для создания прокси объекта указателя на инстанс и защищающий его мутекс, таким образом и сам инстанс и защищающий его мутекс повязаны вместе, нету возможности добратся до экземпляра без инициализации мутекса любому другому объекту даже глобальному. Так же решается проблема очередности, возможностью взятия адреса этого хранилища, что приведет к форсированию его создания, без создания инстанса. Что перекрывает все дыры, непонимаю, почему у александресу так сложно все было придумано через Lifetime, когда можно было просто гарантировано пропихнуть на стек более важный объект. Осталась тока одна дыра, которую вообще не представляю как решать ибо она какая то циклическая — это инициализация самого мутекса, если форсировать задержку через Sleep и долбится сразу другими потоками, то вроде прошибается. Просто если сделать еще одну обрамляющую секцию инициализации, то ее опять таки надо лочить статическим мутексом, и опять приходим к тому, что если не успеваем в первом потоке завершить полное создание муткса, то можем получить fail.
Эх, иметь бы некий 100% сконструированный объект синхронизации.
Здравствуйте, Аноним, Вы писали:
А>Я не много не понял, как будет работать счетчик шварца в конкретной задаче ? если он будет просто инициализировать мутекс при необходимости в каждой единице трансляции, то в этом нету смысла.
Здравствуйте, Kolobrodin, Вы писали:
K>Здравствуйте, Kolobrodin, Вы писали:
K>>Здравствуйте, Аноним, Вы писали:
K>Вот примерчик, выдрал из проекта:
K>.hpp:
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 мы можем использовать в конструкторах глобальных объектов.
Неоконченная мысль всегда казалась Шри Япутре слишком
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 на базе интрелокед функций, но имхо, это не тот случай, чтобы огород городить, если бы был "стандартный" то это было бы супер
Здравствуйте, Аноним, Вы писали:
>>Здравствуйте, 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 на базе интрелокед функций, но имхо, это не тот случай, чтобы огород городить, если бы был "стандартный" то это было бы супер
Здравствуйте, Kolobrodin, Вы писали:
K>С таким же успехом можно было заюзать:
K>static InstanceTypeRef getInstance() K>{ K> static InstanceType s_instance; K> return s_instance; K>}
K>И надо сказать, это кое-где работает
простите, что немного офтоп, но нельзя ли пояснить, что тут не так? На практике проблем не было (гцц), и я так понимаю гцц это дело поддерживает, но может какие-то там ещё проблемы глубже, очень хотелось бы понять.
Здравствуйте, brankovic, Вы писали:
B>простите, что немного офтоп, но нельзя ли пояснить, что тут не так? На практике проблем не было (гцц), и я так понимаю гцц это дело поддерживает, но может какие-то там ещё проблемы глубже, очень хотелось бы понять.
Но обычно хотят singleton близкий по описанию к singleton с двумя проверками, чтобы под другими компиляторами (MSVC) тоже работало. Ну, и соответственно, пиплы, программирующие исключительно под MSVC, на собеседованиях относятся к варианту от gcc крайне скептически и готовы прямо в митингруме расжечь костер и наказать еретика. Несмотря на то, что старательно объясняешь разницу, они не могут поверить, что компилятор может следить... Доставляет, однако.
Неоконченная мысль всегда казалась Шри Япутре слишком
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 написать
Здравствуйте, andrey.desman, Вы писали:
AD>Здравствуйте, Kolobrodin, Вы писали:
K>>Надо чаще на старый код смотреть. Зачем-то static в namespace засунул
AD>Раз уж на то пошло, то можно еще и spinlock_data выровнять.
Спасибо А как это лучше сделать инновационным способом?
ЗЫ. Как там в Индусии?
Неоконченная мысль всегда казалась Шри Япутре слишком
Здравствуйте, Kolobrodin, Вы писали:
AD>>Раз уж на то пошло, то можно еще и spinlock_data выровнять. K>Спасибо А как это лучше сделать инновационным способом?
struct sdata
{
int dummy;
char data[sizeof(spinlock)];
} spinlock_data;
Но здесь теоритических гарантий на выравнивание нет, хотя на практике ни один из компиляторов не будет мусорить дырками между dummy и data.
Как-то сталкивался с такой проблемой, когда портировал код на более старый армовский компилятор. Там std::wstring вылетал в конструкторе по умолчанию из-за невыровненных данных. Да, там тоже выделяли память статик чаром под единый инстанс пустой строки Задолбался я тогда ковыряться в недрах того STL, продираясь сквозь все эти жутко нечитаемые шаблоны в шаблонах и #ifdef.
K>ЗЫ. Как там в Индусии?
Дурдом там Пришел к выводу, что все это нужно только чтобы увидеть красивую картинку перед смертью
Здравствуйте, andrey.desman, Вы писали:
AD>Здравствуйте, Kolobrodin, Вы писали:
AD>>>Раз уж на то пошло, то можно еще и spinlock_data выровнять. K>>Спасибо А как это лучше сделать инновационным способом?
AD>А х.з. AD>Можно так: 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>Дурдом там Пришел к выводу, что все это нужно только чтобы увидеть красивую картинку перед смертью
Неоконченная мысль всегда казалась Шри Япутре слишком
Здравствуйте, Kolobrodin, Вы писали:
K>Предположение, что данные, кратные по размеру некоторому X, компилятор пытается разместить по кратному X адресу? Иначе смысла не вижу.
Пытается? Нечеткая логика, ха.
У разных базовых типов разное выравнивание на разных платформах и даже компиляторах. И компилятор обязан это выравнивание соблюсти, если не сказано иначе (типа packed, __align__ и т.д.).
Смысл в том, чтобы использовать тип с максимальным выравниванием, тогда любые данные по этому адресу будут выровнены.
Максимальное выравнивание, которое мне известно, имеет long double на 64-битном линуксе (16 байт), так что тут int ничего не решает, если внутри spinlock есть long double
Здравствуйте, andrey.desman, Вы писали:
AD>Смысл в том, чтобы использовать тип с максимальным выравниванием, тогда любые данные по этому адресу будут выровнены.
Я вот это не догнал Выравнивание размера или выравнивание адреса и как оно взаимосвязано?
Неоконченная мысль всегда казалась Шри Япутре слишком
Здравствуйте, 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;
Здравствуйте, 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>
Здравствуйте, andrey.desman, Вы писали:
AD>Это как минимум три разных операции (если смотреть не самый низкий уровень): выделение памяти, вызов конструкторов, запись в переменную. Последние два компилятор/процессор может распараллелить или поменять местами.
1. std::string* str = new std::string("abc");
2. str->data();
что в точке 2 str будет указывать на какой-то объект класса std::string, который ещё не сконструирован строкой "abc" из-за переупорядочивания инструкций компилятором/процессором
Здравствуйте, баг, Вы писали:
баг>Не верю.
Счастливой отладки!
баг>Это всё равно, что сказать баг>
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[5]: Как защитить mutex singletona
От:
Аноним
Дата:
13.04.11 17:07
Оценка:
Здравствуйте, баг, Вы писали:
баг>Здравствуйте, andrey.desman, Вы писали:
AD>>Это как минимум три разных операции (если смотреть не самый низкий уровень): выделение памяти, вызов конструкторов, запись в переменную. Последние два компилятор/процессор может распараллелить или поменять местами.
баг> Вы хотите сказать, что
баг>
мутекс статический! соответсвенно первый поток может войти и инициировать его конструктор, а второй, зайдя будет подразумевать, что мутекс создан, и в точке захвата будет undefined behavior, если первый не успеет его инициализировать. Если вам это интересно, то в другой(более длинной) ветке обсуждение этой фичи.