Locking ostream output in macro

475 Views Asked by At

I have this code for some proprietary logger:

#define LOG GetStream()

Where GetStream returns an std::ostream. User will do:

LOG << "text";

I need this to be thread safe but would like to avoid this:

#define END Unlock();
#define LOG Lock(); GetStream() << "text" << END;

Since user will need to add the "END":

LOG << "Text" << END;

Any ideas?

Remark: I handle the carriage return using something like this.

3

There are 3 best solutions below

1
On

One way to solve this is to use function-style macros, where you incorporate the locking/unlocking by using a C++ block and scoping:

#define LOG(output)               \
    do                            \
    {                             \
        LockingClass lock;        \
        GetStream() << output;    \
    } while (0)

The LockingClass (or whatever you want to name it) is a scoped lock, which locks the stream on construction, and unlocks it in on destruction.

Could be used like e.g.

LOG("hello variable is " << variable);

Can't use it with expressions containing comma though, the preprocessor will interpret commas as argument separator for the macro. Could probably be solved with variadic macros.

4
On

TL;TD: you can't make the whole x<<text<<end work only by macros.

in order to put many expressions with a semicolon (;) with a macro , the only valid way is using the do{..} while(0) statement , you can read about it more here : do { ... } while (0) — what is it good for?

now, all good until you want to use some operators like <<, then you can't use the do{..} while(0) costruct.

my suggestion : wrap the std::ostream in a class where you overload the << operator. inside the overload , call Lock and Unlock.

struct MyLogger{
  std::ostream& operator << (Text text){
    Lock();
    stream <<text;
    Unlock();
    return stream;
  }
}

where stream is the stream you stream the text into.

now, you can create an object from this class and use regular, non-macro <<:

NyLogger Log;
Log << text;
1
On

Just though of this:

#define LOG for (int i = 0 ;i < 1 ;i++,(i == 1 ? Unlock())) LockAndGetStream()