I'm have a multithreaded program that prints to the console in hundreds of places. Unfortunately, instead of
Line 2
Line 1
Line 3
I get
Line2Line1
Line3
I am trying to make puts
thread safe.
In Python (which I don't think has this problem, but suppose it did), I'd do
old_print = print
print_mutex = threading.Lock()
def print(*args, **kwargs):
print_mutex.acquire()
try:
old_print(*args, **kwargs)
finally:
print_mutex.release()
I'm trying this in Ruby,
old_puts = puts
puts_mutex = Mutex.new
def puts(*args)
puts_mutex.synchronize {
old_puts(*args)
}
But this doesn't work: "undefined method old_puts
"
How can I make thread-safe (i.e. not print partial lines)?
To make these classes thread-safe, you must prevent concurrent access to the internal state of an instance by more than one thread. Because Java was designed with threads in mind, the language provides the synchronized modifier, which does just that.
the standard C printf() and scanf() functions use stdio so they are thread-safe.
A side note: std::cout is thread-safe Each character will atomically be written.
alias old_puts puts
or more modern way:
module MyKernel
PutsMutex = Mutex.new
def puts(*)
PutsMutex.synchronize{super}
end
end
module Kernel
prepend MyKernel
end
The reason for this behaviour is that puts
internally calls the underlying write
function twice - one for the actual value to be written, and one for the newline to be written. (Explained in Ruby's puts is not atomic)
Here's a hack to make puts
call write
exactly once: Append \n
to the string you're writing. Here's what this looks like in my code:
# Threadsafe `puts` that outputs text and newline atomically
def safe_puts(msg)
puts msg + "\n"
end
puts
internally checks whether the object being written has a newline at the end, and only calls write
again if that isn't true. Since we've changed the input to end with a newline, puts
ends up making only one call to write
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With