2015-12-11 3 views
5

У меня есть многопоточная программа, которая печатает на консоли в сотнях мест. К сожалению, вместоMake puts thread-safe

Line 2 
Line 1 
Line 3 

Я получаю

Line2Line1 

Line3 

Я пытаюсь сделать puts поточно.


В Python (который я не думаю, что есть такая проблема, но предполагаю, что это сделал), я бы

old_print = print 

print_mutex = threading.Lock() 

def print(*args, **kwargs): 
    print_mutex.acquire() 
    try: 
     old_print(*args, **kwargs) 
    finally: 
     print_mutex.release() 

Я пытаюсь это в Рубине,

old_puts = puts 

puts_mutex = Mutex.new 

def puts(*args) 
    puts_mutex.synchronize { 
     old_puts(*args) 
    } 

Но это не работает: "неопределенный метод old_puts"


Как сделать потокобезопасным (т. не печатать отдельные строки)?

+4

Совет: когда вы делаете 'old_puts = puts', вы неявно выполняете' old_puts = puts() ' –

ответ

6
alias old_puts puts 

или более современный способ:

module MyKernel 
    PutsMutex = Mutex.new 
    def puts(*) 
    PutsMutex.synchronize{super} 
    end 
end 

module Kernel 
    prepend MyKernel 
end 
+2

« modern »= Ruby 2.0+ –

0

Причиной такого поведения является то, что puts внутренне вызывает лежащую write функцию дважды - один за действительное значение, которое будет написано, и один для перевода строки в быть написано. (Разъяснения в Ruby's puts is not atomic)

Вот хак сделать puts вызов write ровно один раз: Append \n на строку, которую вы пишете. Вот как это выглядит в моем коде:

# Threadsafe `puts` that outputs text and newline atomically 
def safe_puts(msg) 
    puts msg + "\n" 
end 

puts внутренне проверяет, имеет ли объект записывается символ новой строки в конце, и вызывает только write снова, если это не так. Так как мы изменили ввод до конца с помощью новой строки, puts заканчивает выполнение только одного вызова write.