#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)