Reputation: 2884
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
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
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
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
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