Потокобезопасный синглтон

Февраль 17, 2010

Как известно, классический синглтон Мейерса не является потокобезопасным.

После осознания этого факта, программист проходит обычно следующую цепочку действий:

1) Вставляет критическую секцию на все тело метода «получение экземпляра»

2) Осознает, что это неэффективно, и применяет double-check lock

3) Обнаруживает, что double-check lock не обеспечивает 100% потокобезопасность, и начинает это лечить (см. volatile, memory barriers и т.п.)

Грустная правда заключается в том, что, поскольку в нынешней версии стандарта С++ ничего нет на тему потоков, решения которое было бы абсолютно переносимо на любую платформу (компилятор + ОС + железо) не существует. На эту тему есть статья Мейерса. Однако для VC++ и IA32-64 есть вполне простое работающее решение (к сожалению, в статье об этом не говорится, поэтому она производит неоднозначное впечатление).

Дискуссии на эту тему есть здесь:

http://rsdn.ru/forum/cpp.applied/3545271.aspx

http://www.rsdn.ru/forum/cpp.applied/3234750.all.aspx

http://www.rsdn.ru/forum/cpp/531461.flat.4.aspx

http://rsdn.ru/forum/cpp.applied/3545271.aspx

. В общем и целом, достаточно классического double-check lock + применения volatile – указателей на создаваемый объект + приравнивания статического указателя на объект к свежесозданному объекту через 1) временную переменную 2) InterlockExchange с этой временной переменной. На указанной архитектуре и с указанным компилятором это приведет к барьерам памяти в нужных местах. Попозже выложу код.

PropertyPage Apply

Декабрь 14, 2009

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

Объяснение. Логика пользователя такова – изменения, сделанные до нажатия на эту кнопку, должны обязательно запоминаться. Даже если потом будет нажато cancel, или диалог закрыт «крестиком»  ЭТИ изменения должны быть сохранены. А те изменения, которые были сделаны после нажатия на Apply, разумеется, при нажатии на Cancel НЕ должны применяться. Это не позволяет повесить применение всех изменений на OnClose.

Надо сказать, в очередной раз раздражает то, что DoDataExchange (SaveAndValidate) всегда вызывается при покидании данной Propertypage. Это не зависит от того, посылалось ли в PropertySheet PSM_CHANGED Более того, я не нашел способ внутри Propertypage понять, установлен ли этот флаг. Таким образом, сохранение данных ВСЕГДА происходит при покидании PropertyPage

Проблемы с CValueDlg

Октябрь 30, 2009

Проблема заключается в том, что рекурсия изменений (изменение присылается в сам источник изменений, например значение параметра фильтра – в методику, которая и апдейтила CValueDlg ) заблокирована в самом CValueDlg  (т.е. он не будет обрабатывать изменение, если он источник изменений), но не заблокирована в обратном направлении со стороны хранителя значения. Она происходит постольку, поскольку соотв. сообщение WM_VALUEDLG рассылается из DoDataExchange, если bSaveAndValidate = false, либо если источник UpdateData (true) – edit, т.е. реально во всех случаях, когда что-то делается в DoDataExchange.

Непонятно, почему из DoDataExchange(FALSE), т.е. в ситуации, когда ValueDlg отображает изменения внсенные снаружи, он присылает это сообщение. Это вроде бы неправильно.

Неправильный подход заключается в том, что изменения вносимые изнутри (нажатия на плюс-минус, и т.д.) применяются посредством вызова UpdateData (FALSE). Таким образом, поскольку SetValue тоже (и это как раз правильно) вызывает UpdateData (FALSE), объединяются совершенно различные ситуации: изменение снаружи и изменение изнутри диалога.

Исправление:

DoDataExchange(FALSE) в не должен рассылать сообщение WM_VALUEDLG. Он вызывается, когда требуется обновление контролов диалога в соотв. с измененным значением; это ситуация, обратная той о которой должно сигнализировать сообщение WM_VALUEDLG (и соотв. оно должно рассылаться при DoDataExchange(TRUE)).

Со своей стороны , кнопки плюс минус и т.д. должны в конечном счете приводить а) к DoDataExchange(FALSE) б) к рассылке сообщения.

Можно сделать функцию ChangeValueFromInside()

{UpdateData(FALSE); SendMessage(WM_VALUEDLG)}

SetValue должен применять DoDataExchange(FALSE)? но  не должен высылать сообщение WM_VALUEDLG. Оно должно высылаться только если произошла внутренняя (в диалоге) редакция значения. Рассылка нового значения по разным окнам (если такая требуется –надо проанализировать все вызовы SetValue) должна делаться как-то по-другому.

vector _bool_

Октябрь 15, 2009

Драфт нового стандарта C0x вызывает у меня последнее время все больше вопросов. Такое впечатление,  что господа Страуструп, Саттер и компания даже не подчистили проблемы, известные со времен обсуждения предыдущего C98. Вот яркий пример.

Еще в 98-99 годах активно высказывались мнения (упомянутого Саттера), что описание vector<bool> в стандарте С98 содержит внутреннее противоречие – данный контейнер не является стандартным, а также является underspecified.

Еще ДО принятия C98 делались попытки разрешить эту ситуацию, но к сожалению безрезультатно. Как с некой суммой информации об этом (а также, если кто-то подзабыл – в чем собсна проблема) можно ознакомиться вот с этой статьей.

Поскольку в большинстве статей по проблеме, которые я видел, люди пишут что-то вроде

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

vector<bool> vb;
...//init vb
bool *b = &vb[0];

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

Для начала – чем хорош нынешний vector<bool>? Он оптимизирует место, занимаемое контейнером. Когда это полезно? Когда массив очень большой. А какие еще проблемы у нас возникнут при работе с большим массивом, помимо места? Скорость, разумеется. Проблема не в том, что как пишут здесь , «1 Кб никого не парит», а в том что эта оптимизация места оборачивается пессимизацией скорости – не «потенциально», а 100% кинетически, если вы работаете с большими массивами bool, т.е. сохраняете их, копируете, передаете каким-то другим модулям. Благодаря невозможности получить указатели на кусок памяти, занимаемый нужным фрагментом контейнера, для нас закрыта возможность работать через быстрые «старорежимные» rtl-фунции типа memcpy ( или скажем fwrite, который сработает в несколько раз быстрее, чем всякие там ostream_iterator(ofstream_object) ). Т.е. примененная «оптимизация для больших объемов» при работе с оными создаст вам гораздо более грозные проблемы, чем те что она решает. Это известно с 90-х годов, но в Dinkumware STL, которую использует VS 2005, у vector<bool> по-прежнему нет методов получения вожделенного указателя, хотя от рождения есть всякие нестандартные flip, и можно было бы добавить еще. Это означает, что vector<bool> – «политический труп», на который давно махнули рукой, и все рекомендуют его просто игнорировать.

Что же мы видим в драфте нового стандарта (вот его позднейший кусочек про сабж) ? А ничего.  Все та же мутная херня, что и была в предыдущем стандарте. Те же пожелания реализовывать vector<bool> с упаковкой в биты. Даже не потрудились переименовать vector<bool> в bit_vector, чтобы люди могли легко получить нормальную, не проксированную реализацию vector<bool>.

RIP Concepts

Октябрь 9, 2009

In July 2009 the C++ standards committee decided to remove concepts from the C++0x by an unprecedented move
Аллилуйя!!!

Вот выкинули бы нахер еще всякие shared_ptr и было бы ваще счастье.

PS «Slowpoke detected» – yeah I know.

GdiPlus::MeasureString

Октябрь 7, 2009

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


GetClientRect(rectBnd);

graphics.MeasureString(L"", -1, font, pointOrigin/*origin*/, stringFormat, rectBnd/*in:rectBound, out:rectResult*/);

rectBnd == Rect(ClientRect.UpperLeft(),  ClientRect.UpperLeft()), т.е. 0,0,0,0

а не rectBnd == Rect(pointOrigin, pointOrigin)

Поэтому если попытаться потом сделать

rect(pointOrigin, rectResult.bottomright()),

то получишь прямоугольник у которого левый бок правее правого бока.

сукасука

Акселераторы

Июль 22, 2009

Задавать в качестве акселераторов не VK, а просто символы можно только для тех клавиш, которые являются латинскими буквами. Для остальных надо использовать VK_OEM_*

Например если нужен акселератор «правая квадратная скобка» следует ставить VK_OEM_6. Если поставить «]» – не будет работать.

О приоритете операторов

Июнь 2, 2009

LPDWORD pdwCountsReceived = …;

*pdwCountsReceived=0; //все верно

*pdwCountsReceived++; //++ выполнится прежде *, инкрементируется указатель а не содержимое

NK6 Presentation 24_04_09

Май 5, 2009

NK 6.0.0.2

Май 3, 2009

Второй релиз вылетел из гнезда.

NK 6.0.0.2

Исправления и улучшения см в readme

Из существенных для любопытствующих – есть демосигнал, работает без усилителя.

Для этого, сразу после логина, нажать на кнопку с шестеренками, на вкладке «Общие» выбрать «MBN-20 демо» и закрыть – открыть заново НК6

Пора бы и поставить за деньги, только вот некому – 2009 год продажами НК пока не ознаменовался.


Follow

Get every new post delivered to your Inbox.