UPDATE
Обновление может быть плохим после принятия ответа, но оригинал немного вводит в заблуждение. То, будет ли ruby делать отдельный вызов write(2)
для автоматически добавляемой новой строки, зависит от состояния буферизации выходного объекта ввода-вывода.
$stdout
(при подключении к tty) обычно буферизуется строкой, поэтому эффект puts()
- при заданной строке разумного размера - с неявно добавленной новой строкой - это один вызов write(2)
. Однако в случае с IO.pipe
и $stderr
, как обнаружил ОП, это не так.
ОРИГИНАЛЬНЫЙ ОТВЕТ
Измените свой главный аргумент pipe.puts()
на символ новой строки, оканчивающийся строка:
pipe.puts "##{c} ... #{i}\n" # <-- note the newline
Почему? Вы устанавливаете pipe.sync
в надежде, что запись в канал будет атомарной и без чередования, поскольку они (предположительно) меньше PIPE_BUF
байтов. Но это не сработало, потому что реализация puts()
канала ruby делает отдельный вызов write (2) для добавления завершающего символа новой строки , и поэтому ваши записи иногда чередуются там, где вы ожидали новую строку.
Вот подтверждающий отрывок из следующей строки вашего сценария:
$ strace -s 2048 -fe trace=write ./so-1326067.rb
....
4574 write(4, "#0:12 tiga => 3, 3 => tiga #0:12", 32) = 32
4574 write(4, "\n", 1)
....
Но добавление собственного символа новой строки решает проблему, обеспечивая передачу всей вашей записи за один системный вызов:
....
5190 write(4, "#194:41 tujuh => 7, 7 => tujuh #194:41\n", 39 <unfinished ...>
5179 write(4, "#183:38 enam => 6, 6 => enam #183:38\n", 37 <unfinished ...>
....
Если по какой-то причине это не может работать для вас, вам придется координировать мьютекс между процессами (например, File.flock()
).