Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Вызов callback'а в контексте другого потока


Автор: borisbn 28.5.2013, 18:37
Здравствуйте.

Есть класс, который получает в конструкторе callback (указатель на функцию или шаблонный параметр типа Callable - не важно) и запускает отдельный поток. При наступлении какого-то события необходимо вызвать callback, но так, чтобы он был вызван в контексте потока, который создал класс. В Windows я могу использовать SendMessage для перехода из рабочего потока в главный, но хотелось бы кроссплатформенного решения, но без Qt (с последним я знаю как сделать то, что хочу).

Код (убрал не имеющее отношение к делу, например деструктор и т.п.) :
Код
struct ThreadWrap {
    ThreadWrap( void(*callback)() )
        : m_thread( & ThreadWrap::treadFunc, this, callback )
    {
        cout << std::this_thread::get_id() << endl; //                  ( 1 )
    }
private:
    std::thread m_thread;
    void treadFunc( void(*callback)() ) {
        while ( ! m_abort ) {
            // при каком-то условии
            callback();
           // эта функция вызовется из моего/рабочего/дополнительного потока,
           // а я хочу, чтобы из потока, создавшего класс ThreadWrap
        }
    }
};

// где-то в другом месте
void foo() {
    cout << std::this_thread::get_id() << endl; //                  ( 2 )
}
ThreadWrap tw( foo );


Другими словами, я хочу, чтобы в ( 1 ) и ( 2 ) напечаталось одно и то же. М.б. в конструкторе этот std::this_thread::get_id() нужно сохранять, но как потом сказать при вызове callback'а что его (callback) нужно вызвать в том самом потоке ?

Спасибо.

Автор: feodorv 28.5.2013, 19:29
Разве поток, который создал класс, не должен просто дожидаться указанного события, а при его наступлении вызвать callback()?

Автор: mes 28.5.2013, 19:36
чтоб вызвать что то в другом потоке, надо соеденинить оба потока очередью, из котороой целевой поток будет брать что пришло и вызывать это..  Если вы хотите, чтоб в целевом потоке приходяшие события обрабатывались параллельно основной работе, нужно разбить его работу на составлящие, между выполнениями которых опрашивать очередь. Оно же событейная модель с точки зрения кутэ или же асинхронная с точки зрения asio..

Добавлено через 4 минуты и 51 секунду
конечно можно использовать и синхронную модель, но она в принципе является частным случаем, кода размер очереди равняется единице..

Автор: xvr 29.5.2013, 13:08
Сформулирую то, что сказал mes немного попроще. Что бы что то вызвать в другом потоке, в этом другом потоке должна быть точка синхронизации - именно в ней и будет произведен вызов этого 'чего то'. Вызвать нечто в совершенно неопределенном месте любого потока невозможно, т.к. при вызове поток должен находится в консистентном состоянии, т.е. ваш вызов должен быть естественным образом вложен в текущий стековый фрейм, а это можно сделать только там, где изначально предусматривался вызов функции.

NB. Вызов на стеке-прерывании не рассматриваем. Это можно сделать, но очень черевато неожиданными сломами в самых неожиданных местах.

Автор: borisbn 29.5.2013, 13:33
Всем спасибо за ответы. 

В Windows есть очередь сообщений, через которую можно послать событие о том, что нужно что-то вызвать. В linux, подозреваю, тоже есть нечто подобное. В Qt сделали так, что обращение к этим очередям для меня прозрачно (коннектишь сигнал к слоту и всё), но я не хочу в данном конкретном случае использовать Qt. Была надежда, что либо в C++11 (какой-нибудь std::this_thread::call_from_other) либо в boost (где-нибудь в дебрях asio) либо ещё в какой-нибудь header-only библиотеке это тоже реализовано...
Жаль. Я, конечно, подозревал, что никакой магии не существует, но... надежда умирает последней...

Ещё раз спасибо. Закрываю.

Автор: mes 30.5.2013, 17:44
Цитата(borisbn @  29.5.2013,  12:33 Найти цитируемый пост)
либо в boost (где-нибудь в дебрях asio) 

так асио оно само и есть для этого smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)