Commit 809d62c7 authored by Pavel Vainerman's avatar Pavel Vainerman

(EventLoopServer): с promise/future какие-то проблеммы

(возможно при совместной работе с libev). Вернулся на использование std::condition_variable
parent ceb9fce3
......@@ -16,7 +16,7 @@
Name: libuniset2
Version: 2.6
Release: alt30
Release: alt31
Summary: UniSet - library for building distributed industrial control systems
License: LGPL
......@@ -508,6 +508,9 @@ rm -f %buildroot%_libdir/*.la
# history of current unpublished changes
%changelog
* Sat Jun 03 2017 Pavel Vainerman <pv@altlinux.ru> 2.6-alt31
- (EventLoopServer): refactoring start process
* Sat Jun 03 2017 Pavel Vainerman <pv@altlinux.ru> 2.6-alt30
- test build (devel)
......
......@@ -49,7 +49,7 @@ namespace uniset
* Т.к. evprepare необходимо вызывать из потока в котором крутится event loop (иначе libev не работает),
* а функция run() в общем случае вызывается "откуда угодно" и может быть вызвана в том числе уже после
* запуска event loop, то задействован механизм асинхронного уведомления (см. evprep, onPrepapre) и ожидания
* когда произойдёт инициализация при помощи promise/future (см. реализацию evrun()).
* на condition_variable, когда произойдёт инициализация (см. реализацию evrun()).
*/
class CommonEventLoop
{
......
......@@ -33,7 +33,7 @@ namespace uniset
virtual void evprepare() {}
// Управление потоком событий
bool evrun( bool thread = true );
bool evrun( bool thread = true, size_t waitRunningTimeout_msec = 60000 );
void evstop();
ev::dynamic_loop loop;
......@@ -41,13 +41,20 @@ namespace uniset
private:
void onStop() noexcept;
void defaultLoop( std::promise<bool>& prepareOK ) noexcept;
void defaultLoop() noexcept;
bool waitDefaultLoopRunning( size_t waitTimeout_msec );
void onLoopOK( ev::timer& t, int revents ) noexcept;
std::atomic_bool cancelled = { false };
std::atomic_bool isrunning = { false };
ev::async evterm;
std::shared_ptr<std::thread> thr;
std::mutex looprunOK_mutex;
std::condition_variable looprunOK_event;
std::atomic_bool looprunOK_state;
ev::timer evruntimer;
};
// -------------------------------------------------------------------------
} // end of uniset namespace
......
......@@ -11,6 +11,9 @@ namespace uniset
{
evterm.set(loop);
evterm.set<EventLoopServer, &EventLoopServer::onStop>(this);
evruntimer.set(loop);
evruntimer.set<EventLoopServer, &EventLoopServer::onLoopOK>(this);
}
// -------------------------------------------------------------------------
EventLoopServer::~EventLoopServer()
......@@ -19,26 +22,24 @@ namespace uniset
evstop();
}
// ---------------------------------------------------------------------------
bool EventLoopServer::evrun( bool thread )
bool EventLoopServer::evrun( bool thread, size_t timeout_msec )
{
if( isrunning )
return true;
isrunning = true;
std::promise<bool> p;
auto prepareOK = p.get_future();
if( !thread )
{
defaultLoop(p);
return prepareOK.get();
defaultLoop(); // <-- здесь бесконечный цикл..
return false;
}
else if( !thr )
thr = make_shared<std::thread>( [ &p, this ] { defaultLoop(std::ref(p)); } );
bool ret = prepareOK.get();
if( !thr )
thr = make_shared<std::thread>( [&] { defaultLoop(); } );
bool ret = waitDefaultLoopRunning(timeout_msec);
// если запуститься не удалось
if( !ret && thr )
{
......@@ -81,13 +82,17 @@ namespace uniset
loop.break_loop(ev::ALL);
}
// -------------------------------------------------------------------------
void EventLoopServer::defaultLoop( std::promise<bool>& prepareOK ) noexcept
void EventLoopServer::defaultLoop() noexcept
{
evterm.start();
// нам нужен "одноразовый таймер"
// т.к. нам надо просто зафиксировать, что loop начал работать
evruntimer.start(0);
try
{
evprepare();
prepareOK.set_value(true);
while( !cancelled )
{
......@@ -104,10 +109,33 @@ namespace uniset
catch( std::exception& ex )
{
cerr << "(EventLoopServer::defaultLoop): " << ex.what() << endl;
prepareOK.set_value(false);
}
looprunOK_state = false;
looprunOK_event.notify_all();
isrunning = false;
}
// -------------------------------------------------------------------------
bool EventLoopServer::waitDefaultLoopRunning( size_t waitTimeout_msec )
{
std::unique_lock<std::mutex> lock(looprunOK_mutex);
looprunOK_event.wait_for(lock, std::chrono::milliseconds(waitTimeout_msec), [&]()
{
return (looprunOK_state == true);
} );
return looprunOK_state;
}
// -------------------------------------------------------------------------
void EventLoopServer::onLoopOK( ev::timer& t, int revents ) noexcept
{
if( EV_ERROR & revents )
return;
looprunOK_state = true;
looprunOK_event.notify_all();
t.stop();
}
// -------------------------------------------------------------------------
} // end of uniset namespace
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment