Is Ruby's Stdlib Logger Class Thread-Safe

Is Ruby's stdlib Logger class thread-safe?

A quick look at logger.rb reveals code such as the following:

def write(message)
@mutex.synchronize do
if @shift_age and @dev.respond_to?(:stat)
begin
check_shift_log
rescue
raise Logger::ShiftingError.new("Shifting failed. #{$!}")
end
end
@dev.write(message)
end
end

So while I can't vouch for whether it gets thread-safety correct, I can confirm that it is making a concerted effort to do it right!

P.S. It's often easy to answer questions like this for yourself by reading the code :-)

Can Ruby's stdlib Logger class safely handle writers from multiple processes?

Yes, you can safely write interleaved log data to a single logfile in the way you've described.

However, you're better off logging a separate log for each process or using a consolidated logging system like syslog. Here's a couple of reasons why:

  • Log Rotation/Management: truncating/rolling logfiles is difficult when you have to coordinate signalling multiple processes
  • Interleaved data can be confusing even if you're injecting the PID to disambiguate

I'm currently managing a number of Resque workers per system with a single logfile and wish I had separated a logfile for each worker. It's been difficult debugging issues and managing the logs properly.

C++ Thread-Safe Map

Does not meet the criteria that you have specified, but you could have a look at the TBB containers. There is so called concurrent_hash_map which allows multiple threads to access concurrently the data in the map. There are some details, but everything is nicely documented and can give you an idea of the "concurrent container". Depending on your needs this might be totally inappropriate...

What happens when you don't join your Threads?

After writing the question out, I realized that this is the exact thing that a web server does when serving pages. I googled and found the following article of a Ruby web server. The loop code looks pretty much like mine:

loop do
session = server.accept
request = session.gets
# log stuff

Thread.start(session, request) do |session, request|
HttpServer.new(session, request, basePath).serve()
end
end

Thread.start is effectively the same as Thread.new, so it appears that letting the threads finish and die off is OK to do.

How to increment (add value to) decimal in a thread-safe way?

Using lock is not overkill. It is required.

Structure types like System.Decimal are never atomic, it also doesn't fit the native cpu word size. Which is why Interlocked doesn't have an overload for it either.



Related Topics



Leave a reply



Submit