2015-12-11 14 views
5

Tôi có một chương trình đa luồng in ra bảng điều khiển ở hàng trăm địa điểm. Thật không may, thay vìĐặt các chủ đề an toàn

Line 2 
Line 1 
Line 3 

tôi nhận được

Line2Line1 

Line3 

Tôi cố gắng để làm cho puts chủ đề an toàn.


Trong Python (mà tôi không nghĩ rằng có vấn đề này, nhưng giả sử nó đã làm), tôi muốn làm

old_print = print 

print_mutex = threading.Lock() 

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

Tôi đang cố gắng này trong Ruby,

old_puts = puts 

puts_mutex = Mutex.new 

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

Nhưng điều này không hoạt động: "phương pháp không xác định old_puts"


Làm cách nào để tạo an toàn cho luồng (tức là không in một phần dòng)?

+4

Mẹo: khi bạn thực hiện 'old_puts = puts', bạn đang làm ngầm' old_puts = puts() ' –

Trả lời

6
alias old_puts puts 

hoặc cách hiện đại hơn:

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

module Kernel 
    prepend MyKernel 
end 
+2

" hiện đại "= Ruby 2.0+ –

0

Lý do cho hành vi này là puts nội bộ gọi là cơ bản write chức năng hai lần - một cho giá trị thực tế được viết, và một cho xuống dòng để được viết. (Giải thích trong Ruby's puts is not atomic)

Đây là một hack để thực hiện puts gọi write chính xác một lần: Nối \n vào chuỗi bạn đang viết. Đây là những gì này trông giống như trong mã của tôi:

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

puts nội bộ kiểm tra xem đối tượng được viết có một dòng mới ở cuối, và chỉ gọi write một lần nữa nếu đó là không đúng sự thật. Vì chúng tôi đã thay đổi đầu vào để kết thúc bằng một dòng mới, puts kết thúc chỉ thực hiện một cuộc gọi đến write.