#define BOOST_THREAD_USE_LIB
//-------------------------------------------------------------------------
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
//-------------------------------------------------------------------------
#include <string>
#include <iostream>
//-------------------------------------------------------------------------
/*
g++ -Wall -o ./main ./main.cpp -lboost_thread
*/
//-------------------------------------------------------------------------
class Example
{
private:
typedef boost::shared_mutex WaiterSharedMutex;
typedef boost::shared_lock<WaiterSharedMutex> WaiterSharedLock;
typedef boost::defer_lock_t DeferredLock;
boost::thread workThread;
WaiterSharedMutex waiterMutex;
boost::posix_time::time_duration sleepTime;
void WorkThread(void)
{
while(true)
{
WaiterSharedLock wsl(waiterMutex,DeferredLock());
if(wsl.timed_lock(boost::get_system_time() + sleepTime))
{
std::cerr << "Forced exit from thread" << std::endl;
return;
}
std::cerr << "Work of thread" << std::endl;
}
return;
}
public:
Example(std::size_t timeToSleep) : sleepTime(boost::posix_time::milliseconds(timeToSleep))
{
waiterMutex.lock();
return;
}
~Example(void)
{
waiterMutex.unlock();
workThread.join();
return;
}
bool Start(void)
{
bool result = false;
if(workThread.joinable() == false)
{
waiterMutex.try_lock();
workThread = boost::thread(boost::bind(&Example::WorkThread,this));
result = true;
}
return result;
}
bool Stop(void)
{
bool result = false;
waiterMutex.unlock();
if(workThread.joinable() == true)
{
workThread.join();
}
return result;
}
};
//-------------------------------------------------------------------------
int main(int argc,char** argv)
{
std::string input;
Example example(50000);
while(true)
{
input.clear();
std::cout << ":> ";
std::cin >> input;
if(!input.compare("quit"))
{
break;
}
else if(!input.compare("start"))
{
example.Start();
}
else if(!input.compare("stop"))
{
example.Stop();
}
}
return 0;
}
Временная задержка выполнения потока обеспечивается ожиданием на mutex-е функцией timed_lock, а возможность немедленного завершения потока тем, что как сам mutex, так и его блокировка являются разделяемыми (shared_mutex и shared_lock). У разделяемого mutex-а есть две возможных блокировки: эксклюзивная, и разделяемая. Если на mutex-е эксклюзивная блокировка -- заблокировать его разделяемой будет невозможно. Обратное тоже верно. Но эксклюзивную блокировку может создавать только один поток, а разделяемую -- несколько. В представленном примере на mutex ставится эксклюзивная блокировка в конструкторе класса (строка 40), и перед попыткой пересоздать поток (строка 54). Поток (потоки), которому требуется выполнять в цикле некую функцию, пытается получить разделяемую блокировку на mutex (строка 28). Завершиться успехом это может только в случае, если основной поток отпустит эксклюзивную блокировку (строка 63, и вызов функции Stop в деструкторе класса). После чего требуется лишь дождаться завершения потока (потоков) функцией join.
понедельник, 26 сентября 2011 г.
Контролируемый выход из цикла в потоке
В своей деятельности я часто использую потоки. Как правило, из библиотеки boost::thread. На пару с boost::bind возможности получаются впечатляющие. Если поток однократно выполняет какое-либо действие, и сам завершается -- всё хорошо. Но зачастую требуется, чтобы поток выполнял это действие в цикле, через заданный временной интервал, и был способен получать уведомления о завершении своей работы от основного потока приложения. Для подобных целей я использую следующий механизм, основанный на совместном использовании boost::shared_mutex и boost::shared_lock:
Подписаться на:
Комментарии (Atom)