Boost logo

Boost Users :

Subject: Re: [Boost-users] Waiting for a thread on another thread
From: Benedetto Proietti (bproietti_at_[hidden])
Date: 2010-03-05 12:06:32


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 don’t 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_at_[hidden]
[mailto:boost-users-bounces_at_[hidden]] On Behalf Of Daniel Lidström
Sent: Friday, March 05, 2010 7:22 AM
To: boost-users_at_[hidden]
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_at_[hidden]

http://lists.boost.org/mailman/listinfo.cgi/boost-users

 



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net