473,511 Members | 16,983 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

How to add thread-safety in a logging library?

Hi,

I implemented a small logging library with the API like this:

[snip]
logger& log = log_manager::instance().get_logger("my_logger");
log.stream(DEBUG) << "this is a debug message" << std::endl;
log.stream(INFO) << "this is an info message" << std::endl;
[/snip]

Every logger has a unique name, and manages an output stream
(std::ostream). The 'stream(log_level_t)' member function returns an
ostream_proxy object, which is implemented as the following:

[snip]
class ostream_proxy {

public:

// other member functions...

template<typename T>
ostream_proxy& operator<<(T const& t) {
(*os_) << t;
return *this;
}

private:
std::ostream* os_; // ostream_proxy objects from the same logger
object share
// the same output stream.
};
[/snip]

Thus it is possible that two threads retrieve the same logger object
and write messages to the logging stream at the same time.

Now i want to add thread-safety to my logging library, and i realize
that in ostream_proxy, the statement "(*os_) << t;" is not thread-safe
(std::ostream is not thread-safe, right?). So i need to re-implement
the operator << in ostream_proxy like this:

[snip]
class ostream_proxy {

public:

// other member functions...

template<typename T>
ostream_proxy& operator<<(T const& t) {
{
boost::mutex::scoped_lock lock(*os_mutex_);
(*os_) << t;
}
return *this;
}

private:
std::ostream* os_; // ostream_proxy objects from the same
logger object
boost::mutex* os_mutex_; // share the same output stream and the
same mutex.
};
[/snip]

In this way, i can guarantee that at any moment, there is at most one
thread that calls "(*os_) << t;".

But since logging may be an action that is frequently performed, the
code above may be too expensive to bear... Surely i can use a policy
to allow user to choose if s/he want thread-safety or not. But in a
multi-threaded application, user still has to pay for logging...

So i would like to know if such implementation is proper, or if there
is a way to make that better.

I would appreciate your advice. Thanks!

Aug 3 '07 #1
2 4034
On 2007-08-03 12:27, ZHENG Zhong wrote:
Hi,

I implemented a small logging library with the API like this:

[snip]
logger& log = log_manager::instance().get_logger("my_logger");
log.stream(DEBUG) << "this is a debug message" << std::endl;
log.stream(INFO) << "this is an info message" << std::endl;
[/snip]

Every logger has a unique name, and manages an output stream
(std::ostream). The 'stream(log_level_t)' member function returns an
ostream_proxy object, which is implemented as the following:

[snip]
class ostream_proxy {

public:

// other member functions...

template<typename T>
ostream_proxy& operator<<(T const& t) {
(*os_) << t;
return *this;
}

private:
std::ostream* os_; // ostream_proxy objects from the same logger
object share
// the same output stream.
};
[/snip]

Thus it is possible that two threads retrieve the same logger object
and write messages to the logging stream at the same time.

Now i want to add thread-safety to my logging library, and i realize
that in ostream_proxy, the statement "(*os_) << t;" is not thread-safe
(std::ostream is not thread-safe, right?). So i need to re-implement
the operator << in ostream_proxy like this:

[snip]
class ostream_proxy {

public:

// other member functions...

template<typename T>
ostream_proxy& operator<<(T const& t) {
{
boost::mutex::scoped_lock lock(*os_mutex_);
(*os_) << t;
}
return *this;
}

private:
std::ostream* os_; // ostream_proxy objects from the same
logger object
boost::mutex* os_mutex_; // share the same output stream and the
same mutex.
};
[/snip]

In this way, i can guarantee that at any moment, there is at most one
thread that calls "(*os_) << t;".
I have not given this issue a lot of though but with the code above you
protect each << operation with a lock, however if you have two threads
running and both have a statement like this:

log.stream(DEBUG) << "Foo: " << foo << ", Bar: " << bar << std::endl;

(i.e. multiple << on one line) you only lock each << and there can be
interleaving from multiple threads giving you a result like this in the log:

Foo: Foo: 4 Bar: 32 Bar: 5
But since logging may be an action that is frequently performed, the
code above may be too expensive to bear... Surely i can use a policy
to allow user to choose if s/he want thread-safety or not. But in a
multi-threaded application, user still has to pay for logging...

So i would like to know if such implementation is proper, or if there
is a way to make that better.

I would appreciate your advice. Thanks!
Locks are usually more expensive if they are heavily contended, so if
you have many threads that perform logging (or a few threads which logs
a lot) then you might want to consider giving each thread its own,
thread local, log.

--
Erik Wikström
Aug 3 '07 #2
On Fri, 03 Aug 2007 10:27:02 -0000, ZHENG Zhong wrote:
>I implemented a small logging library with the API like this:
[snip]
logger& log = log_manager::instance().get_logger("my_logger");
log.stream(DEBUG) << "this is a debug message" << std::endl;
log.stream(INFO) << "this is an info message" << std::endl;
[/snip]
[...]
>Thus it is possible that two threads retrieve the same logger object
and write messages to the logging stream at the same time.
This is because you use the Singleton Anti-pattern for your logger. If
you created a logger object for each thread and passed it to the
functions (or passed a context object that provides access to the
logger) you would not run into the problems you describe.
>Now i want to add thread-safety to my logging library, and i realize
that in ostream_proxy, the statement "(*os_) << t;" is not thread-safe
(std::ostream is not thread-safe, right?). So i need to re-implement
the operator << in ostream_proxy like this:
[...]
>But since logging may be an action that is frequently performed, the
code above may be too expensive to bear.
If you insist on using global objects try TLS
(http://en.wikipedia.org/wiki/Thread-local_storage) and let each
thread write to a different logging handler.
--
Roland Pibinger
"The best software is simple, elegant, and full of drama" - Grady Booch
Aug 4 '07 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
2153
by: adeger | last post by:
Having trouble with my first forays into threads. Basically, the threads don't seem to be working in parallel (or you might say are blocking). I've boiled my problems to the following short code...
4
2874
by: Gilles Leblanc | last post by:
Hi I have started a small project with PyOpenGL. I am wondering what are the options for a GUI. So far I checked PyUI but it has some problems with 3d rendering outside the Windows platform. I...
6
2316
by: Tony Proctor | last post by:
Hi everyone We're experiencing some serious anomalies with the scheduling of ASP threads. I'd be interested to hear if anyone knows what algorithm is used (e.g. simple round-robin, or something...
7
2685
by: Ivan | last post by:
Hi I have following problem: I'm creating two threads who are performing some tasks. When one thread finished I would like to restart her again (e.g. new job). Following example demonstrates...
4
5417
by: Matthew Groch | last post by:
Hi all, I've got a server that handles a relatively high number of concurrent transactions (on the magnitude of 1000's per second). Client applications establish socket connections with the...
5
2815
by: Razzie | last post by:
Hi all, A question from someone on a website got me thinking about this, and I wondered if anyone could explain this. A System.Threading.Timer object is garbage collected if it has no...
16
3286
by: droopytoon | last post by:
Hi, I start a new thread (previous one was "thread timing") because I have isolated my problem. It has nothing to do with calling unmanaged C++ code (I removed it in a test application). I...
9
3050
by: mareal | last post by:
I have noticed how the thread I created just stops running. I have added several exceptions to the thread System.Threading.SynchronizationLockException System.Threading.ThreadAbortException...
7
2671
by: Charles Law | last post by:
My first thought was to call WorkerThread.Suspend but the help cautions against this (for good reason) because the caller has no control over where the thread actually stops, and it might have...
3
34938
by: John Nagle | last post by:
There's no way to set thread priorities within Python, is there? We have some threads that go compute-bound, and would like to reduce their priority slightly so the other operations, like...
0
7144
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7356
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7427
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
7085
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
1
5069
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4741
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3214
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1577
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
449
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.