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

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

(возможно при совместной работе с libev). Вернулся на использование std::condition_variable
parent ceb9fce3
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
Name: libuniset2 Name: libuniset2
Version: 2.6 Version: 2.6
Release: alt30 Release: alt31
Summary: UniSet - library for building distributed industrial control systems Summary: UniSet - library for building distributed industrial control systems
License: LGPL License: LGPL
...@@ -508,6 +508,9 @@ rm -f %buildroot%_libdir/*.la ...@@ -508,6 +508,9 @@ rm -f %buildroot%_libdir/*.la
# history of current unpublished changes # history of current unpublished changes
%changelog %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 * Sat Jun 03 2017 Pavel Vainerman <pv@altlinux.ru> 2.6-alt30
- test build (devel) - test build (devel)
......
...@@ -49,7 +49,7 @@ namespace uniset ...@@ -49,7 +49,7 @@ namespace uniset
* Т.к. evprepare необходимо вызывать из потока в котором крутится event loop (иначе libev не работает), * Т.к. evprepare необходимо вызывать из потока в котором крутится event loop (иначе libev не работает),
* а функция run() в общем случае вызывается "откуда угодно" и может быть вызвана в том числе уже после * а функция run() в общем случае вызывается "откуда угодно" и может быть вызвана в том числе уже после
* запуска event loop, то задействован механизм асинхронного уведомления (см. evprep, onPrepapre) и ожидания * запуска event loop, то задействован механизм асинхронного уведомления (см. evprep, onPrepapre) и ожидания
* когда произойдёт инициализация при помощи promise/future (см. реализацию evrun()). * на condition_variable, когда произойдёт инициализация (см. реализацию evrun()).
*/ */
class CommonEventLoop class CommonEventLoop
{ {
......
...@@ -33,7 +33,7 @@ namespace uniset ...@@ -33,7 +33,7 @@ namespace uniset
virtual void evprepare() {} virtual void evprepare() {}
// Управление потоком событий // Управление потоком событий
bool evrun( bool thread = true ); bool evrun( bool thread = true, size_t waitRunningTimeout_msec = 60000 );
void evstop(); void evstop();
ev::dynamic_loop loop; ev::dynamic_loop loop;
...@@ -41,13 +41,20 @@ namespace uniset ...@@ -41,13 +41,20 @@ namespace uniset
private: private:
void onStop() noexcept; 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 cancelled = { false };
std::atomic_bool isrunning = { false }; std::atomic_bool isrunning = { false };
ev::async evterm; ev::async evterm;
std::shared_ptr<std::thread> thr; 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 } // end of uniset namespace
......
...@@ -11,6 +11,9 @@ namespace uniset ...@@ -11,6 +11,9 @@ namespace uniset
{ {
evterm.set(loop); evterm.set(loop);
evterm.set<EventLoopServer, &EventLoopServer::onStop>(this); evterm.set<EventLoopServer, &EventLoopServer::onStop>(this);
evruntimer.set(loop);
evruntimer.set<EventLoopServer, &EventLoopServer::onLoopOK>(this);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
EventLoopServer::~EventLoopServer() EventLoopServer::~EventLoopServer()
...@@ -19,26 +22,24 @@ namespace uniset ...@@ -19,26 +22,24 @@ namespace uniset
evstop(); evstop();
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
bool EventLoopServer::evrun( bool thread ) bool EventLoopServer::evrun( bool thread, size_t timeout_msec )
{ {
if( isrunning ) if( isrunning )
return true; return true;
isrunning = true; isrunning = true;
std::promise<bool> p;
auto prepareOK = p.get_future();
if( !thread ) if( !thread )
{ {
defaultLoop(p); defaultLoop(); // <-- здесь бесконечный цикл..
return prepareOK.get(); 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 ) if( !ret && thr )
{ {
...@@ -81,13 +82,17 @@ namespace uniset ...@@ -81,13 +82,17 @@ namespace uniset
loop.break_loop(ev::ALL); loop.break_loop(ev::ALL);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
void EventLoopServer::defaultLoop( std::promise<bool>& prepareOK ) noexcept void EventLoopServer::defaultLoop() noexcept
{ {
evterm.start(); evterm.start();
// нам нужен "одноразовый таймер"
// т.к. нам надо просто зафиксировать, что loop начал работать
evruntimer.start(0);
try try
{ {
evprepare(); evprepare();
prepareOK.set_value(true);
while( !cancelled ) while( !cancelled )
{ {
...@@ -104,10 +109,33 @@ namespace uniset ...@@ -104,10 +109,33 @@ namespace uniset
catch( std::exception& ex ) catch( std::exception& ex )
{ {
cerr << "(EventLoopServer::defaultLoop): " << ex.what() << endl; cerr << "(EventLoopServer::defaultLoop): " << ex.what() << endl;
prepareOK.set_value(false);
} }
looprunOK_state = false;
looprunOK_event.notify_all();
isrunning = false; 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 } // 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