Queequeg
Queequeg

Reputation: 2884

Synchronize entire class in C++11

Look at this simple logging class (only relevant parts here):

class Logger {
public:
    void log(string& msg){
        //lock for all instances
        cout << "[" << tag << "] " << msg;
        //unlock
    }
private:
     string tag;

};

What is the easiest way to synchronize the entire class (not instances) so that separate instances of Logger (in different threads) write to cout sequentially (not all at once) ?

Upvotes: 2

Views: 5252

Answers (4)

S S
S S

Reputation: 1

//use c++ 11 mutex

class CircularQueue
{
protected:
    int * data;
    int head;
    int tail;
    int size;
    std::mutex queueMutex;
public:
    CircularQueue(void);
    int dequeue();
    void enqueue(int x);
    void initialize(int size);
    virtual ~CircularQueue(void);
};



CircularQueue::CircularQueue(void)
{
    data = 0x0;
    head = -1;
    tail = -1;
    size=0;
}

int CircularQueue::dequeue()
{
    if(tail == head)
    {
        throw "empty queue!";
    }
    std::lock_guard<std::mutex> lock(queueMutex);

    int result = data[head];
    head ++;
    if(head >= size) 
    {
        head =head % size;
    }

    return result;
}


void CircularQueue::enqueue(int x)
{

    std::lock_guard<std::mutex> lock(queueMutex);
    data[tail] = x;
    tail ++;
    if(tail >= size)
    {
        tail = tail % size;
    }
    if(tail == head)
    {
        throw "overflow!";
    }
}

void CircularQueue::initialize(int size)
{
    data = new int[size]; 
    head = 0;
    tail = 0;
    this->size = size;
}

CircularQueue::~CircularQueue(void)
{
    delete [] data;
}

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275750

Short version: Write a synchronized wrapper, wrap std::cout, then use the synchronized cout to write.

Long version:

#include <mutex>

template<typename T>
struct Synchronized {
  explicit Synchronized(T& t_):t(t_) {}

  template<typename Functor>
  auto operator()( Functor&& f ) const->decltype(f(t)) {
    std::lock_guard<std::mutex> guard(myMutex);
    return f(t);
  }
// I could implement these, but I'm lazy:
  Synchronized& operator=(Synchronized const&) = delete;
  Synchronized& operator=(Synchronized &&) = delete;
  Synchronized(Synchronized const&) = delete;
  Synchronized(Synchronized &&) = delete;
private:
  mutable T& t;
  mutable std::mutex myMutex;
};


// in "sync_cout.h"
extern Synchronized<std::ostream> sync_cout;

// in "sync_cout.cpp"
Synchronized<std::ostream> sync_cout(std::cout);

// In "logger.h"

// #include "sync_cout.h"
class Logger {
public:
  void log(string& msg){
    sync_cout( [&](std::ostream& os) {
      os << "[" << tag << "] " << msg;
    });
  }
private:
   string tag;

};

(Stolen from Herb. Any errors in the above are my own, not Herb's.)

For superior performance, the above link also includes a non-blocking asynchronous wrapper.

Upvotes: 3

niXman
niXman

Reputation: 1758

The easiest way to do it:

class Logger {
public:
   void log(std::string& msg){
   //lock for all instances
   {  std::unique_lock<std::mutex> locker(_mut); // or std::lock_guard<std::mutex> locker(_mut);
      std::cout << "[" << tag << "] " << msg;
   } //unlock
private:
   std::string tag;
   static std::mutex _mut;
};

Upvotes: 2

Nikos C.
Nikos C.

Reputation: 51890

The usual way, with a mutex:

#include <mutex>

class Logger {
public:
    void log(string& msg)
    {
        // Lock for all instances
        std::lock_guard<std::mutex> lock(coutMutex);

        cout << "[" << tag << "] " << msg;

        // Unlocking happens automatically since the lock
        // gets destroyed here.
    }

private:
    string tag;
    static std::mutex coutMutex; // Don't forget to define this somewhere.
};

Upvotes: 7

Related Questions