Задача проста.
В другом потоке срабатывает обработчик , по которому я должен запустить функцию в основном потоке и передать 1-2 аргумента.
Второстепенный поток — где срабатывает обработчик, создаю не я — он создаётся в дебрях sdk ,которую я использую.
Всегда писал на QT и там это легко делается, но теперь это надо сделать средставами буста.
Как?
например сохрани функцию с аргументами из вторичного потока в boost::function и дальше в зависимости от того должна ли она выполнится синхронно или асинхронно, 1) нотифицируешь главный поток, а во вторичном ждешь завершения выполнения, например, с помощью boost::condition_variable; 2) кладешь в очередь объект boost::function и также нотифицируешь и продолжаешь работу во вторичном потоке без ожидания.
Здравствуйте, savitar, Вы писали:
S>Здравствуйте, Haccel, Вы писали:
H>>...
S>например сохрани функцию с аргументами из вторичного потока в boost::function и дальше в зависимости от того должна ли она выполнится синхронно или асинхронно, 1) нотифицируешь главный поток, а во вторичном ждешь завершения выполнения, например, с помощью boost::condition_variable; 2) кладешь в очередь объект boost::function и также нотифицируешь и продолжаешь работу во вторичном потоке без ожидания.
Спасибо.
Ну вторичный поток мне никак нельзя тормозить — упаси господь, так что только второй вариант.
Два вопроса
1 — как нотифицировать.
2 — как мне сделать чтобы тот boost::fuction будет выполнен именно в главном потоке.
Здравствуйте, Haccel, Вы писали:
H>Задача проста. H>В другом потоке срабатывает обработчик , по которому я должен запустить функцию в основном потоке и передать 1-2 аргумента. H>Второстепенный поток — где срабатывает обработчик, создаю не я — он создаётся в дебрях sdk ,которую я использую. H>Всегда писал на QT и там это легко делается, но теперь это надо сделать средставами буста. H>Как?
Решение просто.
В обработчике (во второстепенном потоке) взводишь флаг. В основном потоке периодически проверяешь этот флаг и, если он взведен, вызываешь функцию.
Хотя есть у меня подозрение, что ты сам не понимаешь, что тебе нужно. Опиши ситуацию в целом.
31.07.2010 10:37, Haccel пишет: > > Задача проста. > В другом потоке срабатывает обработчик , по которому я должен запустить > функцию в основном потоке и передать 1-2 аргумента.
Такая функциональность заложена в boost::asio:
// io_service.run() вызывается в основном потоке:
asio::io_service io_service;
io_service.run();
// В параллельном потоке делаешь так:
io_service.dispatch(bind(&func_of_two_argumnts, 10, 432.12));
// А это ф-ция, которая вызовется из основного потока:void func_of_two_argumnts(int a, float b)
{
cout << a << " " << b << end;
};
M>Хотя есть у меня подозрение, что ты сам не понимаешь, что тебе нужно. Опиши ситуацию в целом.
Я прекрасно понимаю. Я постоянно это делаю. Это легко делается в Qt (сгнально-слотовым соединением) и легко под iphone(mac)(есть метод в NSObject типа который вызывает функцию в главном потоке). Но теперь мне нужно универсальное решение для этих платформ. А qt под iphone не пашет.
Ситуция такова. В главном потоке запущена LUA скрипт-машина. Мне нужно в скрипте вызвать обработчик — это можно только из главного потока. Но событие происходит в другом потоке. Оттуда нельзя дёргать lua — прога падает.
Твой вариант не очень понятен/удобен . Как мне в главном потоке постоянно проверять флаг? Это довольно часто придётся делать и опять таки — аснихронно, поток то главный своим делом занят? Проясни...
Здравствуйте, ArtDenis, Вы писали:
AD>31.07.2010 10:37, Haccel пишет: >> >> Задача проста. >> В другом потоке срабатывает обработчик , по которому я должен запустить >> функцию в основном потоке и передать 1-2 аргумента.
AD>Такая функциональность заложена в boost::asio: AD>
AD>// io_service.run() вызывается в основном потоке:
AD>asio::io_service io_service;
AD>io_service.run();
AD>// В параллельном потоке делаешь так:
AD>io_service.dispatch(bind(&func_of_two_argumnts, 10, 432.12));
AD>// А это ф-ция, которая вызовется из основного потока:
AD>void func_of_two_argumnts(int a, float b)
AD>{
AD> cout << a << " " << b << end;
AD>};
AD>
Спасибо. Не понятно, когда вызывать io_service.run. Если сделать как написано , то io_service просто вхолостую сработает если ему не дать работы. Если run сделать после dispatch то всё сработает как надо — в главном потоке, но главная проблема то не решена — как мне узнать , когда вызывать Io_service.run , главный поток же не знает когда это нужно сделать.Как его известить о событии?
Здравствуйте, Haccel, Вы писали:
H>Спасибо. Не понятно, когда вызывать io_service.run. Если сделать как написано , то io_service просто вхолостую сработает если ему не дать работы. Если run сделать после dispatch то всё сработает как надо — в главном потоке, но главная проблема то не решена — как мне узнать , когда вызывать Io_service.run , главный поток же не знает когда это нужно сделать.Как его известить о событии?
Идея такая, что в приложении главный поток выполняет различную инициализацию, а потом вызывает io_service.run(). В io_service.run() он и "крутится", ожидая поступления команды на выполнение. io_service.dispatch() гарантирует, что ф-ция будет вызвана в том же самом потоке, в котором был произведён вызов io_service::run(), io_service::run_one(), io_service::poll() или io_service::poll_one(): http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/reference/io_service/dispatch.html
Здравствуйте, Haccel, Вы писали:
H>Два вопроса H>1 — как нотифицировать.
через ту же CV, если конечно приемлимо в основном потоке замирать. или из основного потока поллить что-нибудь. H>2 — как мне сделать чтобы тот boost::fuction будет выполнен именно в главном потоке.
ее самому нужно выполнить из него.
boost::asio:io_service — замечательное решение, но если все приложение основано на этом, что бы оно все держалось так сказать на boost::asio:io_service::run(), тогда все решается естественным образом. а как тебя сейчас устроено, может сделать на такой манер?
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, Haccel, Вы писали:
H>>Спасибо. Не понятно, когда вызывать io_service.run. Если сделать как написано , то io_service просто вхолостую сработает если ему не дать работы. Если run сделать после dispatch то всё сработает как надо — в главном потоке, но главная проблема то не решена — как мне узнать , когда вызывать Io_service.run , главный поток же не знает когда это нужно сделать.Как его известить о событии?
AD>Идея такая, что в приложении главный поток выполняет различную инициализацию, а потом вызывает io_service.run(). В io_service.run() он и "крутится", ожидая поступления команды на выполнение. io_service.dispatch() гарантирует, что ф-ция будет вызвана в том же самом потоке, в котором был произведён вызов io_service::run(), io_service::run_one(), io_service::poll() или io_service::poll_one(): AD>http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/reference/io_service/dispatch.html
Это я всё знаю... Но моё приложение — какое я пишу , разрабатывается уже более года и переписывать его под io_service.run нереально.
По любому благодарен за совет но проблема осталась...
Так решения я не нашёл.
Пару последних лет я пишу строго на qt и без него растерялся слегка.
Там пишешь просто connect(...,SLOT(),..,SIGNAL(),Qt::QueuedConnection);
И всё таки, как же поступают программситы СИшники кому надо например из неГУИшных потоков воздействовать на ГУИ (без QT)? Это же аналогичная ситуация. Это требуется постоянно, как же это все решают???. ГУИшный поток не может ничего ждать — он занят ГУИ и реакцией на действия юзера.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Haccel, Вы писали:
H>>Два вопроса H>>1 — как нотифицировать. А>через ту же CV, если конечно приемлимо в основном потоке замирать. или из основного потока поллить что-нибудь. H>>2 — как мне сделать чтобы тот boost::fuction будет выполнен именно в главном потоке. А>ее самому нужно выполнить из него.
А>boost::asio:io_service — замечательное решение, но если все приложение основано на этом, что бы оно все держалось так сказать на boost::asio:io_service::run(), тогда все решается естественным образом. а как тебя сейчас устроено, может сделать на такой манер?
Это понятно.Со всем согласен. Мои два вопроса не совсем корректны, это скорее один вопрос. Как из другого потока позвонить в главный. Может UNIX-овые сигналы спасут? Хотелось бы узнать от спецов все варианты. Всю сеть перерыл, ничего не нашёл.
Что такое CV? Но нверно не вариант, раз поток должен мёрзнуть — там же ГУИ...
Здравствуйте, Haccel, Вы писали:
H>И всё таки, как же поступают программситы СИшники кому надо например из неГУИшных потоков воздействовать на ГУИ (без QT)? Это же аналогичная ситуация. Это требуется постоянно, как же это все решают???. ГУИшный поток не может ничего ждать — он занят ГУИ и реакцией на действия юзера.
Ну тогда пиши что-то платформозависимое. Ты же просил решение из буста
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, Haccel, Вы писали:
H>>И всё таки, как же поступают программситы СИшники кому надо например из неГУИшных потоков воздействовать на ГУИ (без QT)? Это же аналогичная ситуация. Это требуется постоянно, как же это все решают???. ГУИшный поток не может ничего ждать — он занят ГУИ и реакцией на действия юзера.
AD>Ну тогда пиши что-то платформозависимое. Ты же просил решение из буста
Ну я так и поступил уже, но думал есть более 'правильное' решение...
то на чем лупится (не знаю как лучше сказть) твой главный поток туда и нотифицируй и там выполняй ранее сохраненное во вторичном. CV == condition variable.
H>Так решения я не нашёл. H>Пару последних лет я пишу строго на qt и без него растерялся слегка. H>Там пишешь просто connect(...,SLOT(),..,SIGNAL(),Qt::QueuedConnection);
H>И всё таки, как же поступают программситы СИшники кому надо например из неГУИшных потоков воздействовать на ГУИ (без QT)? Это же аналогичная ситуация. Это требуется постоянно, как же это все решают???. ГУИшный поток не может ничего ждать — он занят ГУИ и реакцией на действия юзера.
Я делал так, поток обработки мог сохранять свое состояние. И было некое пустое состояние. Вначале запускал поток с пустым состоянием, и он его изменял. Когда надо чего-то спросить у юзера background thread умирал, отдавая состояние, юзер отвечал и с сохраненным состоянием background thread запускался снова. Немного похоже на coroutine
Здравствуйте, savitar, Вы писали:
S>Здравствуйте, Haccel, Вы писали:
S>то на чем лупится (не знаю как лучше сказть) твой главный поток туда и нотифицируй и там выполняй ранее сохраненное во вторичном. CV == condition variable.
Понятно, но лупление — платформозависимо, а искал кросс-кплатформенное решение...
Здравствуйте, Haccel, Вы писали:
H>Здравствуйте, Mazay, Вы писали:
M>>Хотя есть у меня подозрение, что ты сам не понимаешь, что тебе нужно. Опиши ситуацию в целом.
H>Я прекрасно понимаю. Я постоянно это делаю. Это легко делается в Qt (сгнально-слотовым соединением) и легко под iphone(mac)(есть метод в NSObject типа который вызывает функцию в главном потоке). Но теперь мне нужно универсальное решение для этих платформ. А qt под iphone не пашет.
H>Ситуция такова. В главном потоке запущена LUA скрипт-машина. Мне нужно в скрипте вызвать обработчик — это можно только из главного потока. Но событие происходит в другом потоке. Оттуда нельзя дёргать lua — прога падает. H>Твой вариант не очень понятен/удобен . Как мне в главном потоке постоянно проверять флаг? Это довольно часто придётся делать и опять таки — аснихронно, поток то главный своим делом занят? Проясни...
Как ты себе представляешь "вызов функции в другом потоке" на уровне процессорных инструкций? Ты не можешь просто остановить исполнение потока в случаный момент времени, заставить его исполнять код по другому адресу, а потом вернуть к прерванной работе. Тебе полюбому нужны в главном потоке точки прерывания (хотя бы одна) в которых будет стоять условный переход — обычная работа или обработчик события из параллельного потока.
Qt — есть гуёвая библиотека. Значит у неё в недрах есть большущий цикл обработки сообщений. И все его слоты наверняка сводятся по сути к диспетчеризации приходящих сообщений, а вызов сигнала — к помещению в очередь нужного сообщения. То есть в итоге таже проверка условия в цикле. И да, очень часто это делается. Между отрисовкой, сообщениями таймера, указателя мыши и т. п.
В boost.asio io_service.run() тоже где-то под низом сводится к циклу, на каждом шаге ожидающему события сразу на нескольких объектах. Как только событие произошло, происходит определение типа события (закончилось чтение, закончилась запись, прервали чтение/запись, вызвали io_service.dispatch()) затем — вызов соответствующего обработчика, потом опять ожидание события. Ничего нового.
Я не знаю как работает машина Lua, но наверняка есть какой-то способ снаружи инициировать какое-то событие, на которое есть обработчик на Lua.
Опиши что происходит в главном потоке. Покажи пример правильного дергания lua из того же потока, в котором работает скрипт-машина.
З.Ы.
Что значит "в скрипте вызвать обработчик"? Обработчик написан на скрипте?
Здравствуйте, Mazay, Вы писали:
M>Здравствуйте, Haccel, Вы писали:
H>>Здравствуйте, Mazay, Вы писали:
M>>>Хотя есть у меня подозрение, что ты сам не понимаешь, что тебе нужно. Опиши ситуацию в целом.
M>Как ты себе представляешь "вызов функции в другом потоке" на уровне процессорных инструкций? Ты не можешь просто остановить исполнение потока в случаный момент времени, заставить его исполнять код по другому адресу, а потом вернуть к прерванной работе. Тебе полюбому нужны в главном потоке точки прерывания (хотя бы одна) в которых будет стоять условный переход — обычная работа или обработчик события из параллельного потока.
Первый содержательный ответ... много думал.. согласен.
M>Я не знаю как работает машина Lua, но наверняка есть какой-то способ снаружи инициировать какое-то событие, на которое есть обработчик на Lua.
M>Опиши что происходит в главном потоке. Покажи пример правильного дергания lua из того же потока, в котором работает скрипт-машина.
Здравствуйте, Mazay, Вы писали:
M>Опиши что происходит в главном потоке. Покажи пример правильного дергания lua из того же потока, в котором работает скрипт-машина.
M>З.Ы. M>Что значит "в скрипте вызвать обработчик"? Обработчик написан на скрипте?
#include <iostream>
#include <lua.hpp>
#include <boost/thread.hpp>
void call_handler();
int func(lua_State* );
/*виртуальная машина LUA*/
lua_State* vm;
/*точка входа*/int main()
{
/*инициализация lua*/
vm = lua_open();
lua_register( vm , "cfunc" , func );
/*тестируем верную работу обработчика в главном потоке*/
call_handler();
/*симуляция вызова обработчика в другом потоке*/
boost::thread thread(call_handler);
// тут ,типа, работает ГУЙ
thread.join();
//
std::cin.ignore();
}
/*вызов скриптовой функции*/void call_handler()
{
lua_getglobal( vm , "cfunc" );
assert(LUA_TFUNCTION == lua_type(vm , -1));
lua_call( vm , 0 , 0);
}
int func(lua_State* )
{
std::cout << "LUA handler| thread ->" << boost::this_thread::get_id() << '\n';
return 0;
}
Всё это линкуется с луа либой. Этот код работает. Но в моей проге всё куда сложнее.
Вот почему. В результате этого кода будет два раза вызван обработчик из скрипта — из разных потоков.
Певрый раз из основного — второй из другого.
Но для меня это не допустимо. Оба обработчика должны срабоать в одном потоке.
Потому что юзер в скрипте во второй обработчик навешает кучу всяких вызовов и прога упадёт.
Я это уже проходил — были и race conditions и другие неприятности.
Я давно работаю со скрипт-машинами(не только луа , а и дргугими) и часто выходил из ситуации с помощью платформозависимых механизмов, которые уже описывал здесь, но думал это можно проще сделать с помощью boost. Но теперь понял что наверно решение зависит от плаформы.
Но вообще хотелось бы знать мнение спецов...