
I had a similar problem and I show you how I solved it. The logic a little bit (not sure if you like it, but I find this way to usually be more maintainable and scalable) . Basically the main thread calls Log that pushes the string into a queue. The access to the queue is synchronized by the queue_mutex. There are 2 additional mutexes: · work_mutex makes Run wait until the queue is *not* empty. · empty_mutex makes WaitForQueueFlush wait until the queue *is* empty. Maybe you can achieve the same combining those two mutexes but I dont have time to try that right now. Hope it can help, Benedetto This is an (untested) code snippet. #include <boost/thread/thread.hpp> #include <boost/thread/xtime.hpp> #include <boost/thread/condition.hpp> #include <boost/foreach.hpp> #include <boost/tr1/functional.hpp> #include <queue> #include <fstream> #include <string> class FileLogger { typedef boost::unique_lock<boost::mutex> unique_lock; std::ofstream logfile; bool running; // this controls the actual push/pop in the queue boost::mutex queue_mutex; // this mutex will be "unlocked" when the queue is empty. // WaitForQueueFlush will wait until it is unlocked and then lock it. // It will be unlocked when eventually the queue becomes empty again. boost::mutex empty_mutex; // this mutex will be "locked" when the queue is empty. // the "Run" method will wait on it until some element is pushed into the queue // and this mutex becomes available. boost::mutex work_mutex; // queue seems to be more appropriate data structure than vector std::queue<std::string> queue; // this saves the current thread... just in case you need it boost::thread * mythread; public: FileLogger(const std::string& filename) : logfile(filename.c_str()) , running(true) { work_mutex.lock(); } ~FileLogger() { running = false; } // this runs in the main thread void Log(const std::string& s) { unique_lock lock(queue_mutex); queue.push(s); if (!work_mutex.try_lock()) { work_mutex.unlock(); } if (empty_mutex.try_lock()) { empty_mutex.unlock(); } } void Log_impl(const std::string& s) { unique_lock lock(queue_mutex); logfile << s << '\n'; } void WaitForQueueFlush() { empty_mutex.lock(); } void start() { mythread = new boost::thread(boost::bind(&FileLogger::Run, this)); } private: void Run() { while( running ) { work_mutex.lock(); unique_lock lock(queue_mutex); std::string s = queue.pop(); Log_impl(s); if (queue.empty()) { empty_mutex.unlock(); } } } }; int main() { FileLogger fileLogger("logfile.txt"); fileLogger.Log(std::string(1000*1000, '*')); // this call should wait, synchronously, until // current queue has been flushed to disk fileLogger.WaitForQueueFlush(); } -----Original Message----- From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Daniel Lidström Sent: Friday, March 05, 2010 7:22 AM To: boost-users@lists.boost.org Subject: [Boost-users] Waiting for a thread on another thread Hello! I have created a simple file logger using the active object pattern. This is intended to offload logging operations to a separate thread, to not disturb the main thread with time- consuming file operations. It works very nicely with boost::thread, but now I have a new desired functionality. The file logger keeps an internal queue of strings that need to be written to file. I want to know, from the main thread, when this queue is empty. To illustrate I have created a minimal, hopefully compilable, sample that shows what I am trying to achieve. #include <boost/thread/thread.hpp> #include <boost/thread/xtime.hpp> #include <boost/thread/condition.hpp> #include <boost/foreach.hpp> #include <boost/tr1/functional.hpp> #include <vector> #include <fstream> #include <string> class FileLogger { typedef boost::unique_lock<boost::mutex> unique_lock; std::ofstream logfile; bool running; boost::thread running_thread; boost::mutex mutex; boost::condition_variable condition; std::vector<std::string> queue; public: FileLogger(const std::string& filename) : logfile(filename.c_str()) , running(true) , running_thread(std::tr1::bind(&FileLogger::Run, this)) { } ~FileLogger() { running = false; condition.notify_one(); running_thread.join(); } void Log(const std::string& s) { unique_lock lock(mutex); queue.push_back(s); } void WaitForQueueFlush() { // ?? } private: void Run() { while( running ) { std::vector<std::string> copyList; { // wait 0.1 s here, for queue to fill up boost::xtime sleepTime; boost::xtime_get(&sleepTime, boost::TIME_UTC); sleepTime.nsec += 100*1000*1000; unique_lock lock(mutex); condition.timed_wait(lock, sleepTime); // fetch the current message list copyList.swap(queue); } BOOST_FOREACH(const std::string& s, copyList) { logfile << s << '\n'; } logfile.flush(); } } }; int main() { FileLogger fileLogger("logfile.txt"); fileLogger.Log(std::string(1000*1000, '*')); // this call should wait, synchronously, until // current queue has been flushed to disk fileLogger.WaitForQueueFlush(); } So the problem is to implement FileLogger::WaitForQueueFlush. How can I signal the main thread when the queue has been emptied? Thanks in advance! Regards, Daniel Lidström Stockholm, Sweden _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users