Re[3]: Многопоточный Observer на C++ (практика)
От: remark Россия http://www.1024cores.net/
Дата: 25.11.10 14:38
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

R>Идея была сделать устойчивую финальную версию,

R>промежуточные версии нужны лишь для объяснения проблеммы, и они не тестировались в различных ситуациях.
R>Или вы имели в виду финальную версию?

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


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Многопоточный Observer на C++ (практика)
От: remark Россия http://www.1024cores.net/
Дата: 25.11.10 14:42
Оценка: 1 (1) +1
Здравствуйте, Ryadovoy, Вы писали:

R>Мне попадался проект в котором сплошь и рядом встречались конструкции try{}catch(...){} которые прятали реальные баги.

R>программа не падала, но глючила страшно.
R>Удалось ее нам привести к более менее стабильному состоянию лишь убрав все эти перехватчики.

Бесспорно бывают решения ещё хуже.
Вопрос только, сравнить свою программу с гораздо более плохой и сказать "Ну ничего у меня ещё не худший вариант". Или сравнить свою программу с более хорошей и сказать "А ведь можно сделать лучше".


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Многопоточный Observer на C++ (практика)
От: Alexander G Украина  
Дата: 25.11.10 14:55
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

R>Правильно понял, что signals2 впервые появились в мае 2009-го года,

R>и до этого были лишь signals, которые были не устойчивы к многопоточности?

Да.

R>Есть ли еще какие-нибудь альтернативы?


Думаю, есть.

Я не интересовался, мне не был нужен многопоточный обсервер. (Вообще, мне кажется, трудно быть уверенным в потокобезопасности, когда не уверен, сколько и каких коллбэков вызываются, даже если сама реализация обсервера безопасна.)
Русский военный корабль идёт ко дну!
Re[2]: Многопоточный Observer на C++ (практика)
От: Ryadovoy  
Дата: 25.11.10 14:55
Оценка:
Здравствуйте, remark, Вы писали:

R>Это, конечно, достаточно печально. Выделять память, копировать N памяти, атомарно инкрементировать N счётчиков под мьютексом не айс.


В драйверах, где мне необходима была оптимизация, я избавился от копирования вектора, но та схема была на порядок сложнее.
Там было что-то вроде связного списка, который перебирается под локом (SpeenLock) и инкрементировался счетчик ссылок, а сам вызов происходил уже без лока.
И удаление ячейки из этого списка происходило тоже под этим локом, еще для чего-то была нужна переменная bRemove, уже не припомню.
Но там еще все это усугублялось необходимостью работать на разных уровнях IRQL (PASSIVE_LEVEL, DISPATCH_LEVEL).

Я хотел предоставить схему, которая будет предельно понятна, т.к. тогда при реализации такой схемы меньше шансов допустить ошибку.
Re[4]: Многопоточный Observer на C++ (практика)
От: uzhas Ниоткуда  
Дата: 25.11.10 14:57
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

R>Если необходима обработка нехватки памяти, это делается, но не для примера в статье, вы со мной не согласны?

мне кажется, что зря вы так относитесь к своим "критикам", вам нужно быть сдержанным и мотать на ус ;=)
некоторые вещи режут глаза опытным разработчикам, потому что у них есть хороший багаж опыта, много книжек всяких прочитали от других профи
даже если вы не переносите исключения, то вы все равно могли бы сделать код более качественным с точки зрения поддержки
в этом вам помог бы механизм RAII
он удобен как при исключениях, так и исключение копи-паста, уменьшение _незначащего_ кода
язык С++ достаточно низкоуровневый и очень часто сложно за деревьями увидеть лес, то есть мелочи отвлекают и мешают понять суть
выработаны практики, который частично решают эти проблемы языка и вам их советуют
даже если вы лично не работаете с исключениями. вы могли бы написать код для клиентов, которые работают с ними
и ваш код не пострадал бы
вы могли заметить, что в некоторых функциях перед return у вас стоит Unlock
это и есть проблема в развивающемся коде (то есть не одноразовом коде студента, а коде, который используется\развивается в компании\команде из большого кол-ва разработчиков)
код в большой компании читают очень много, и он должен быть понятен
можно забыть сделать Unlock и это усложняет поддержку кода
именно поэтому в C использовали идиому single function exit point : http://c2.com/cgi/wiki?SingleFunctionExitPoint (чтобы в самом конце освобождать ресурсы)
в C++ это решили через RAII (инструмент не идеальный, ибо плохо дружит с исключениями, но это отдельная холиворная тема, которые тут уже не раз перемалывали)
попробуйте хотя бы частично всосать те советы, которые вам дают
успехов
Re[4]: Многопоточный Observer на C++ (практика)
От: Юрий Жмеренецкий ICQ 380412032
Дата: 25.11.10 14:59
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

ЮЖ>>Теоритически эти проблемы могут возникнуть при возбуждении std::bad_alloc при вставке в вектор (CNotificationDispatcher::Subscribe) :


R>Если необходима обработка нехватки памяти, это делается, но не для примера в статье, вы со мной не согласны?


Здесь не нужна обработка нехватки памяти. Только RAII для lock/unlock. Как миниму в силу того, что на момент написания неизвестны сценарии использования.

R>Наши user-level приложения просто падают когда заканчивается память, и создается креш дамп, ибо странно что закончилась память, неправда-ли?


Что здесь такого странного?
Re[5]: Многопоточный Observer на C++ (практика)
От: Ryadovoy  
Дата: 25.11.10 15:18
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Здесь не нужна обработка нехватки памяти. Только RAII для lock/unlock. Как миниму в силу того, что на момент написания неизвестны сценарии использования.


Рои не панацея, и иногда уменьшают читабельность и понимание происходящего.

1) без роев
void SendNotification(void* pContext)
{
    Lock();
    CNotificationListenerPtrList vListeners = m_vListeners;
    Unlock();

    for(size_t i = 0; i < vListeners.size(); ++i)
    {
        vListeners[i].OnNotification(pContext);
    }
}

2) поменяли на рой, но допустили ошибку, она сразу заметна при сравнении с предыдущим кодом?
void SendNotification(void* pContext)
{
    ScopeLocker scopeLocker(&m_cs);
    CNotificationListenerPtrList vListeners = m_vListeners;

    for(size_t i = 0; i < vListeners.size(); ++i)
    {
        vListeners[i].OnNotification(pContext);
    }
}

3) а надо было вот так.
void SendNotification(void* pContext)
{
    CNotificationListenerPtrList vListeners;
    {
        ScopeLocker scopeLocker(&m_cs);
        vListeners = m_vListeners;
    }
    for(size_t i = 0; i < vListeners.size(); ++i)
    {
        vListeners[i].OnNotification(pContext);
    }
}
Re[5]: Многопоточный Observer на C++ (практика)
От: Ryadovoy  
Дата: 25.11.10 15:37
Оценка:
Здравствуйте, uzhas, Вы писали:

U>мне кажется, что зря вы так относитесь к своим "критикам", вам нужно быть сдержанным и мотать на ус ;=)

Если я был с кем-то резок, прошу извинения, я просто пытаюсь поддерживать беседу.

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

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

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

U>в этом вам помог бы механизм RAII
Этот механизм все же "на любителя"

U>код в большой компании читают очень много, и он должен быть понятен

Механизм RAII не улучшает читабельность кода, и понимание его, что более важно для статьи.
Re[6]: Многопоточный Observer на C++ (практика)
От: gegMOPO4  
Дата: 25.11.10 15:58
Оценка: 1 (1)
Здравствуйте, Ryadovoy, Вы писали:
R>2) поменяли на рой, но допустили ошибку, она сразу заметна при сравнении с предыдущим кодом?

Да, сразу.
Re[6]: Многопоточный Observer на C++ (практика)
От: Юрий Жмеренецкий ICQ 380412032
Дата: 25.11.10 16:01
Оценка: 2 (2)
Здравствуйте, Ryadovoy, Вы писали:

ЮЖ>>Здесь не нужна обработка нехватки памяти. Только RAII для lock/unlock. Как миниму в силу того, что на момент написания неизвестны сценарии использования.


R>Рои не панацея, и иногда уменьшают читабельность и понимание происходящего.



R>1) без роев

R>
R>void SendNotification(void* pContext)
R>{
R>    Lock();
R>    CNotificationListenerPtrList vListeners = m_vListeners;
R>    Unlock();

R>    for(size_t i = 0; i < vListeners.size(); ++i)
R>    {
R>        vListeners[i].OnNotification(pContext);
R>    }
R>}
R>

R>2) поменяли на рой, но допустили ошибку, она сразу заметна при сравнении с предыдущим кодом?
R>
R>void SendNotification(void* pContext)
R>{
R>    ScopeLocker scopeLocker(&m_cs);
R>    CNotificationListenerPtrList vListeners = m_vListeners;

R>    for(size_t i = 0; i < vListeners.size(); ++i)
R>    {
R>        vListeners[i].OnNotification(pContext);
R>    }
R>}
R>

R>3) а надо было вот так.
R>
R>void SendNotification(void* pContext)
R>{
R>    CNotificationListenerPtrList vListeners;
R>    {
R>        ScopeLocker scopeLocker(&m_cs);
R>        vListeners = m_vListeners;
R>    }
R>    for(size_t i = 0; i < vListeners.size(); ++i)
R>    {
R>        vListeners[i].OnNotification(pContext);
R>    }
R>}
R>



Сравниваемые примеры (1 и 3) не равноценны. Аналог для третьего примера должен выглядеть как-то так:

void SendNotification(void* pContext)
{
    CNotificationListenerPtrList vListeners;

    Lock();

    try 
    {
        vListeners = m_vListeners;
    }
    catch(const std::exception&)
    {
        Unlock();
        throw;
    }

    Unlock();

    for(size_t i = 0; i < vListeners.size(); ++i)
    {
        vListeners[i].OnNotification(pContext);
    }
}


Каким образом переписывание такого кода на вариант с использованием RAII уменьшит читабельность?
+ потенциальных мест для ошибок в этом коде больше чем в аналоге с RAII.
+
Re[6]: Многопоточный Observer на C++ (практика)
От: alexeiz  
Дата: 25.11.10 18:56
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

R>Рои не панацея, и иногда уменьшают читабельность и понимание происходящего.


R>3) а надо было вот так.

R>
R>void SendNotification(void* pContext)
R>{
R>    CNotificationListenerPtrList vListeners;
R>    {
R>        ScopeLocker scopeLocker(&m_cs);
R>        vListeners = m_vListeners;
R>    }
R>    for(size_t i = 0; i < vListeners.size(); ++i)
R>    {
R>        vListeners[i].OnNotification(pContext);
R>    }
R>}
R>


Если тебе мешает дополнительный scope, то можно переписать код так:
R>void SendNotification(void* pContext)
{
    ScopeLocker scopeLocker(&m_cs);
    CNotificationListenerPtrList vListeners = m_vListeners;
    scopeLocker.release();  // or you may call it "unlock"

    for(size_t i = 0; i < vListeners.size(); ++i)
    {
        vListeners[i].OnNotification(pContext);
    }
}
Re[6]: Многопоточный Observer на C++ (практика)
От: Mr.Delphist  
Дата: 25.11.10 19:23
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

U>>код в большой компании читают очень много, и он должен быть понятен

R>Механизм RAII не улучшает читабельность кода, и понимание его, что более важно для статьи.

Однажды мне попался код из проекта одного уважаемого разработчика:

GetResource1();
if (!CheckResource1())
{
  FreeResource1();
  return false;
}

GetResource2();
if (!CheckResource2())
{
  FreeResource2();
  FreeResource1();
  return false;
}

GetResource3();
if (!CheckResource3())
{
  FreeResource3();
  FreeResource2();
  FreeResource1();
  return false;
}

...

FreeResource3();
FreeResource2();
FreeResource1();
return true;


Само собой, это упрощенная схема — реальный код был более развесистый. Память не текла лишь при удачном стечении обстоятельств. После замены на RAII оно стало выглядеть вот так:

GuardResource1();
if (!CheckResource1())
  return false;

GuardResource2();
if (!CheckResource2())
  return false;

GuardResource3();
if (!CheckResource3())
  return false;

...

return true;


Конечно, всех проблем это не решило, но темпы утечек серьезно уменьшились. Пострадала ли читабельность?
Re[3]: Многопоточный Observer на C++ (практика)
От: zaufi Земля  
Дата: 25.11.10 20:19
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

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


R>>Общая идея понятна. Детально код не изучал, но что сразу резануло по глазам — небезопасность кода с точки зрения исключений — повсеместно в коде встречаются фрагменты:

R>>
R>>EnterCriticalSection();
R>>//Какие-то операции
R>>LeaveCriticalSection();
R>>

R>>Что если во время выполнения "каких-то операций" возникнет исключение? Почему бы в данном случае не использовать RAII — например, мьютексы и локи из boost::thread?

R>Вы конечно-же со мной не согласитесь, но я считаю что c++ исключения это зло.

а можно узнать почему??? какие ваши аргументы?

R>Я работаю в команде, где не особо ими пользуются (только при необходимости),

мда бывает неприятность... ;( мои соболезнования

R>а необходимости из под колбека выбрасывать исключение нет никакой.

R>bools и stl может выбросить исключение, но оно возможно лишь когда имеет место ошибка программиста
R>(ну или закончилась память в системе, что тоже критично), тогда нужно падать с креш репортом, дабы не скрывать ошибку.
:))))))))
От: rm822 Россия  
Дата: 25.11.10 23:57
Оценка: :)
для 90х это было бы ОК, но на дворе-то 2010й
зачем было разводить столько графоманства, когда современными средствами задача решается тривиально?
пруф-код, слепленый за 5 ммин

struct Subscriber {
    void OnSomething(int asContext) { printf("%i\n", asContext); }
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::set<Subscriber*> subscribers;
    subscribers.insert(new Subscriber());

    int context = 7;
    task_group g;
    g.run( [subscribers,context] { for each(auto s in subscribers) { s->OnSomething(context); }} );
    g.wait();

    return 0;
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Многопоточный Observer на C++ (практика)
От: landerhigh Пират  
Дата: 26.11.10 00:49
Оценка: 1 (1) +5
Здравствуйте, Ryadovoy, Вы писали:

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

U>>в этом вам помог бы механизм RAII
R>Этот механизм все же "на любителя"

Это общепринятый механизм.

Ручные EnterCriticaLSection, LeaveCriticalSection и иже с ними у нас являются поводом к прекращени code review и отправкой его на доработку.
www.blinnov.com
Re[3]: Многопоточный Observer на C++ (практика)
От: jazzer Россия Skype: enerjazzer
Дата: 26.11.10 06:25
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

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

AG>>ну, когда мне такое понадобится, я скорее посмотрю на boost::signals2
R>Спасибо за наводку, я обязательно обращу внимание на signals2.
Имхо, надо было с этого начать. В диссертациях не зря первая глава всегда — это обзор существующих наработок по теме.

R>Моя статья направлена не на то, чтобы дать готовое решение,

R>она объясняет основные принципы, которые применимы там, где boost бывает недоступен (драйвера, нейтивные приложения и т.п.)
с чего бы это буст был там недоступен? и что такое "нейтивные приложения" в контексте С++?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[4]: Многопоточный Observer на C++ (практика)
От: Ryadovoy  
Дата: 26.11.10 10:24
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Имхо, надо было с этого начать. В диссертациях не зря первая глава всегда — это обзор существующих наработок по теме.

Спасибо за замечание, я думаю добавить в статью что-то вроде этого:

По сути я не выдумывал новое решение, я использовал готовый шаблон проектирования,
этот же шаблон использовали и создатели boost, но они разрабатывают именно библиотеку, а не решение для частной ситуации.
boost это огромное количество кода, такое количество кода необходимо, если писать универсальную библиотеку, для частного решения может подойти более простой вариант,
и из-за этого он будет более понятным и легко реализуемым.
Вы досконально понимаете как устроена библиотека signal2 в boost?
лично меня пугает количество кода при вызове колбека, вот стек вызовов.
ObserverTest.exe!TrackedHelloWorld::operator()(int n=2)  Line 30    C++
ObserverTest.exe!boost::detail::function::void_function_obj_invoker1<TrackedHelloWorld,void,int>::invoke(boost::detail::function::function_buffer & function_obj_ptr={...}, int a0=2)  Line 154    C++
ObserverTest.exe!boost::function1<void,int>::operator()(int a0=2)  Line 1013 + 0x1a bytes    C++
ObserverTest.exe!boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker::m_invoke(const boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > & connectionBody={...}, const boost::signals2::detail::void_type * __formal=0x00000000)  Line 352    C++
ObserverTest.exe!boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker::operator()(const boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > & connectionBody={...})  Line 340 + 0x14 bytes    C++
ObserverTest.exe!boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >::dereference()  Line 82 + 0x2d bytes    C++
ObserverTest.exe!boost::iterator_core_access::dereference<boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > >(const boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mut& f={...})  Line 517    C++
ObserverTest.exe!boost::iterator_facade<boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,boost::signals2::detail::void_type,boost::single_pass_traversal_tag,boost::signals2::detail::void_type const &,int>::operator*()  Line 634 + 0xe bytes    C++
ObserverTest.exe!boost::signals2::optional_last_value<void>::operator()<boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > >(boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > first={...}, boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > last={...})  Line 55 + 0x8 bytes    C++
ObserverTest.exe!boost::signals2::detail::combiner_invoker<void>::operator()<boost::signals2::optional_last_value<void>,boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > >(boost::signals2::optional_last_value<void> & combiner={...}, boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > first={...}, boost::signals2::detail::slot_call_iterator_t<boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::slot_invoker,std::list<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> >,std::allocator<boost::shared_ptr<boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > > >::_Iterator<1>,boost::signals2::detail::connection_body<std::pair<enum boost::signals2::detail::slot_meta_group,boost::optional<int> >,boost::signals2::slot1<void,int,boost::function<void __cdecl(int)> >,boost::signals2::mutex> > last={...})  Line 65    C++
ObserverTest.exe!boost::signals2::detail::signal1_impl<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::operator()(int arg1=2)  Line 246 + 0x199 bytes    C++
ObserverTest.exe!boost::signals2::signal1<void,int,boost::signals2::optional_last_value<void>,int,std::less<int>,boost::function<void __cdecl(int)>,boost::function<void __cdecl(boost::signals2::connection const &,int)>,boost::signals2::mutex>::operator()(int arg1=2)  Line 681    C++
ObserverTest.exe!SignalThread(void * pParam=0x00000000)  Line 45    C++


J>с чего бы это буст был там недоступен? и что такое "нейтивные приложения" в контексте С++?

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

Native приложение это приложение, которое может запускатья на ранней стадии загрузки виндовс (например консоль восстановления)
виндовый checkdisk так работает, он запускает c:\WINDOWS\system32\autochk.exe на ранней стадии загрузки. autochk.exe это и есть Native приложение.
Native приложение в основном пользуется лишь экспортом из ntdll.dll (недокументированными функциями), и ничего другого ему не доступно.
У нас по началу были большие трудности с CRT и STL, а вы про boost говорите...
Я Windows программист, и никогда не занимался вопросами переносимости кода на другие платформы,
но думаю что и на других платформах существуют схожие проблемы.
Интересно можно ли при написании модулей ядра в Linux пользоваться библиотеками STL и boost?
Re[7]: Многопоточный Observer на C++ (практика)
От: Ryadovoy  
Дата: 26.11.10 10:36
Оценка: :)
Я думаю что все зависит от кривизны рук, а не от применяемого инструмента или от технологии.
Если разработчик с кривыми руками нужно его гнать в шею и нанять толкового программиста.
Не думайте что я не буду использовать RAII если они будут нужны,
как доказательство могу привести пример моего личного их использования
for(;;)
{
    {   //Enter to notify thread critical section
        CGuard aGuard(m_csNotifyThread);
        if(m_vFilesNotifyQueue.empty())
        {
            if(!str)
            {
                //Scan was completed
                CGuard aGuard(m_csScanState);
                m_nScanState = IFRClient::NotStarted;
            }
            break;
        }
    }

    if(WaitForSingleObject(m_hNotifyThread, 100) != WAIT_TIMEOUT)
    {
        //Something happends with notitification thread, that is error case
        _ASSERT(FALSE);
        CGuard aGuard(m_csScanState);
        m_nScanState = IFRClient::NotStarted;
        break;
    }
}
Re[7]: Многопоточный Observer на C++ (практика)
От: Ryadovoy  
Дата: 26.11.10 10:56
Оценка: +1
Здравствуйте, landerhigh, Вы писали:

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


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

U>>>в этом вам помог бы механизм RAII
R>>Этот механизм все же "на любителя"

L>Это общепринятый механизм.


L>Ручные EnterCriticaLSection, LeaveCriticalSection и иже с ними у нас являются поводом к прекращени code review и отправкой его на доработку.


Я думаю что тематика RAII к данной статье притянута за уши, давайте создадим тему RAII и будем это там это обсуждать?

я так понимаю это вопрос веры для многих поклонников RAII,
по этому я подумаю над тем, чтобы добавить RAII в примеры,
дабы избежать в дальнейшем коментариев насчет RAII.
Re[3]: Многопоточный Observer на C++ (практика)
От: gh2  
Дата: 26.11.10 12:24
Оценка:
Здравствуйте, Ryadovoy, Вы писали:

R>Вы конечно-же со мной не согласитесь, но я считаю что c++ исключения это зло.

R>Я работаю в команде, где не особо ими пользуются (только при необходимости), а необходимости из под колбека выбрасывать исключение нет никакой.
R>bools и stl может выбросить исключение, но оно возможно лишь когда имеет место ошибка программиста
R>(ну или закончилась память в системе, что тоже критично), тогда нужно падать с креш репортом, дабы не скрывать ошибку.

Если класс представлен здесь, значит его предлагается использовать, что в свою очередь влечёт некорректность навязывания своего стиля пользователям.
По-моему, если
1) корректно разрешите проблему безопасности исключений
2) избавитесь от связи (время жизни диспетчера) == (время, проведенное в критической секции)
3) гарантируете отсутствие утечки ресурса "объект-синхронизации" (сейчас это критическая секция)
за приведенный код Вам можно будет сказать спасибо.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.