The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Multi threaded logging


I am currently writing an application that needs to log events from multiple objects to an XML file. These objects are generally running on separate threads. This is in unmanaged C++ . I was wondering if anybody had come across a good solution/design pattern for this problem?

I'm currently looking at setting up a thread safe stream that all objects can log to but it rapidly gets messey and I can't help but think I am missing a simpler solution.


Wednesday, July 18, 2007
I would guess that the general approach is to use a thread-safe, link-list based blocking queue. A worker thread would drain the queue and be blocked until new entries are added. This will allow you to maintain order, while being quite fast. I'm sure there are decent lock-free queue implementations available for C++.

The only concern is that the worker couldn't drain the input fast enough and cause memory issues. I doubt that would happen in practice, though.
Benjamin Manes Send private email
Wednesday, July 18, 2007
I'm not actually aware of any thread safe queue structures as standard in C++. So far as I know STL dosn't handle a situation whereby you have multiple threads writing to say a  vector and then reading from your logging thread.

On the whole C++ seems to have very poor threading capabilities as standard :-(

I can cook something up but it seems like it would be a really common problem and I don't want to re-invent the wheel.

Wednesday, July 18, 2007
I'm sure C++ experts can point you to a free library. In the Java world, Doug Lea's library is standard and now part of the JDK. If you are truly forced to roll your own, it should be a fun excersize. There is enough material freely available online to draw from, such as:
Benjamin Manes Send private email
Wednesday, July 18, 2007
I wrote a thread-safe queue in about 20 minutes. Maybe you're reinventing the wheel, but that's nothing.
Wednesday, July 18, 2007
"On the whole C++ seems to have very poor threading capabilities as standard :-("

The same thing could be said of C for that matter and yet operating systems with concurrent processing functionality are still written to this day using it.

The platform I am assuming is Microsoft Windows since "unmanaged C++" is mentioned directly.  You can use the Windows API directly to create the necessary plumbing for resource locks/unlocks in multi-threaded scenarios to exotic shared memory setups and semaphores or use existing frameworks/libraries as they are everywhere from things like to boost and everything in between.

As far as ISO C++ there is direct support for RAII.  Use this to shield all those points in your codebase where things "rapidly gets messey".  You are correct that there is not built-in support of concurrent programming with C++ but concurrent program is by design and not hacked in or bolted on as doable or some other afterthought.  You specifically ask for good solution/design pattern.  Not being familiar with your specs, goals, and general design other than it IS threaded the only thing I can mention at this time to be helpful is a singleton logger, mutexes for the internal invariants of the logger and scoped locks/unlocks when using said logger as a possible plan of attack but it would seem you already know this much.
Chris Send private email
Thursday, July 19, 2007
If Windows, you can use CThreadPool, or write your own queueing mechanism based on IOCP. You can have multiple produces feed the IOCP queue and have a single consumer service it and log your data. It's very simple.
MBJ Send private email
Thursday, July 19, 2007
thanks guys, it seems the general consensus is that there isn't really a de facto way of doing this but rolling your own isn't that difficult. Pretty much what I thought but I wanted to check as it's always a slap in the face when you go about creating something and find there is something better off the shelf!


Thursday, July 19, 2007
Don't see how it can be much easier than this:

std::vector<LogStuff>  gPendingLogs
CRITICAL_SECITION      gPendingLogsLock;

ClientLog(some stuff...)
  gPendingLogs.push_back(a LogStuff thingy);

        std::vector<LogStuff> localCopy;
        localCopy = gPendingLogs;

        //write contents of localCopy
        //wait until you want to check the queue again
Thursday, July 19, 2007
thanks for taking the time to write code Doug. I've ended up doing basically this but with a stream instead. Seems to work ok for the time being, but I may need to look at a lock free implementation as Ben suggested if the number of log writers grows significantly.

Just a thought; It seems to me that threads are woefully under supported at a language level at present(all languages). Seeing as how multiprocessing is the way forward it would seem prudent to start implementing threading features at a language level asap.

Thursday, July 19, 2007
"it would seem prudent to start implementing threading features at a language level asap."

It is taking place in a standards committee now [ ]. 

Of course a standards committee are infamous for being notoriously slow at producing results in the moving field of technology; or put a different way:  By the time they release the new model and it becomes implemented rather than being some working model theory the landscape has changed enough to have a whole new batch of problems...On top of the problems created by the latest changes.

Dang!  Rockets is hard.
Chris Send private email
Thursday, July 19, 2007
Pull don't push. Queue logsitems in each task and have a separate task pull as many log items as it can when it gets time to poll the log items. Using a circular queue a fast logger won't step on other log sources and you can do work when there's available CPU time.
son of parnas
Friday, July 20, 2007
Please don't expect lock-free. There ain't no free lunch. What might work multi-threaded single-CPU will likely fall apart on a dual-CPU machine.

Big fuss on over an article in Dr. Dobbs that proposed a lock free ring buffer, that fails on multi-CPU.

Better to spend your time making the locked sections as quick as possible.

And of course be sure that it makes a difference. The sample code posted seems unlikely to prove a performance problem unless you have many hundreds of threads hitting the log constantly.
frustrated Send private email
Friday, July 20, 2007
I read the Dobb's article WRT the lock free ring buffer. No way I would trust that thing in multi-core.
Friday, July 20, 2007
Have a looksee at ACE:

It has a distributed logging service (multi-thread, multi-process, multi-machine). Don't know if this would be too heavy-weight a solution for your needs, but it should have everything you need out-of-the-box, batteries included.
Sunday, July 22, 2007
Yeh I had seen some stuff about C++ 0x, if I remember correctly they are pulling a lot of features from Boost. What I really meant is core language features for threading/parallelism. I guess a much more ground up approach. Perhaps could borrow techniques from VHDL (a hardware description language which is inherently parallel). Anyway just musing, I'm sure somebody is working on this right now!

Monday, July 23, 2007
If you're doing C++, there is a fairly new technology which actually puts you ahead of Java/C#. Have a look for OpenMP - it is supported in Intel and MS compilers. It allows you to do threaded code without ever dealing with the threads - you esssentially tell the compiler "multithread this section of code using N" threads.

If anyone's interested in this, I wrote an article on it a while back. It is likley not directly applicable to the poster but it does add much-needed functionality to C++ in a pretty cool way.
Friday, July 27, 2007
If you're taking the lock every time you log a message, this could affect performance if you're really logging a lot of stuff.

You could keep a log queue for each thread (thus no locking), and when it grows big enough, only then take the lock and quickly switch it over to the big writer thread.
Monday, July 30, 2007
John: "If anyone's interested in this, I wrote an article on it a while back. It is likley not directly applicable to the poster but it does add much-needed functionality to C++ in a pretty cool way."

Really cool article. I enjoyed it immensely.

Ok, seriously... It sounds cool, but a link to the article would be much appreciated. It's hard to read it without one.
Ken White Send private email
Tuesday, July 31, 2007

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz