LINUX.ORG.RU

Обьясните суть происходящего при добавлении в stdout «\n»

 , ,


0

7

Первый вариант:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
int main() 
{
 
  printf("1234 ");
  fork();
  exit(0);
}
Выхлоп предсказуем:
faust@localhost 1]$ ./2
1234 1234 [faust@localhost 1]$
Второй вариант:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
int main() 
{
 
  printf("1234 \n");
  fork();
  exit(0);
}
Выхлоп удивил:
[faust@localhost 1]$ ./2
1234 
[faust@localhost 1]$

Может кто-то объяснит что да как?

З.Ы. Собирал просто: gcc -o 2 2.c

★★★★★

Последнее исправление: cetjs2 (всего исправлений: 2)

отложенная запись происходит или по \n или по exit(0), но уже в обеих процессах

anonymous
()
Ответ на: комментарий от anonymous

Нашёл:

в некоторых версиях - перед любой операцией чтения из канала stdin (например, при вызове gets), при условии, что stdout буферизован построчно (режим _IOLBF, смотри ниже), что по-умолчанию так и есть.

Следовательно «\n» скидывает буфер, т.к. заканчивает строку.

drfaust ★★★★★
() автор топика
Ответ на: комментарий от Stil

потому что оба процесса пишут в один и тот же файл/буфер.

drfaust ★★★★★
() автор топика
Последнее исправление: drfaust (всего исправлений: 1)
Ответ на: комментарий от anonymous

обеих процессах

правельней

Ну ничего, скоро снова в школу.

akk ★★★★★
()
Ответ на: комментарий от Stil

|почему?
А теперь вопрос: «Кто именно скидывает буфер?»
Я так понял, что это делает драйвер tty:

[faust@localhost 1]$ ./2 
1234 
[faust@localhost 1]$ ./2 >1
[faust@localhost 1]$ cat ./1
1234 
1234 
[faust@localhost 1]$
В обоих случаях ./2 представляет собой второй вариант, с «\n»

drfaust ★★★★★
() автор топика
Последнее исправление: drfaust (всего исправлений: 1)
Ответ на: комментарий от int13h

Так призови его. Что тут сложного?
sudo cast carb_blog8
А то у меня нет настроения объяснять про работу fork и \a \b \f \n \r \t \v и т.д. А так и Царю развлечение и нам потеха.

peregrine ★★★★★
()
Ответ на: комментарий от int13h

Это последняя цифра года рождения.
</толсто>

По сабжу - ни разу не сишник, интересно.

NeverLoved ★★★★★
()
Последнее исправление: NeverLoved (всего исправлений: 1)
Ответ на: комментарий от drfaust

Стандартный, все-таки си. На нем в 9 раз больше тем.

HerrWeigel ★★★★
()
Ответ на: комментарий от AITap

Это я уже понял. Но почему в обычном stdout система ведет себя по разному - сколько ещё ньюансов должОн учесть программер....
Ведь выхлоп загоняет в блочный pipe уже не прога а терминал/шелл...

drfaust ★★★★★
() автор топика
Ответ на: комментарий от drfaust
$ strace -ff ./a.out
execve("./a.out", ["./a.out"], [/* 41 vars */]) = 0
...
clone(Process 9912 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f06184d49d0) = 9912
[pid  9911] write(1, "1234 ", 5 <unfinished ...>
1234 [pid  9912] write(1, "1234 ", 5 <unfinished ...>
[pid  9911] <... write resumed> )       = 5
1234 [pid  9911] exit_group(0)               = ?
[pid  9912] <... write resumed> )       = 5
[pid  9912] exit_group(0)               = ?
[pid  9911] +++ exited with 0 +++
+++ exited with 0 +++

$ strace -ff ./a.out 
execve("./a.out", ["./a.out"], [/* 41 vars */]) = 0
...
write(1, "1234 \n", 61234
)                  = 6
clone(Process 9901 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f612c91e9d0) = 9901
[pid  9900] exit_group(0)               = ?
[pid  9901] exit_group(0)               = ?
[pid  9900] +++ exited with 0 +++
+++ exited with 0 +++
anonymous
()
Ответ на: комментарий от drfaust

сколько ещё ньюансов должОн учесть программер

это не важно, расценки в резюме

anonymous
()
Ответ на: комментарий от anonymous

По \n флашит ОСь, а не libc. см. посты Обьясните суть происходящего при добавлении в stdout «\n» (комментарий) и Обьясните суть происходящего при добавлении в stdout «\n» (комментарий)

drfaust ★★★★★
() автор топика
Последнее исправление: drfaust (всего исправлений: 1)
Ответ на: комментарий от drfaust

По \n флашит ОСь, а не libc.

А теперь замени printf("1234 "); на write(1, "1234 ", 5);, и подумай ещё раз.

cdslow ★★
()
Ответ на: комментарий от Eddy_Em

Тьфу ты! Дошло: форкнутый процесс унаследовал stdout буфер и по завершению выплюнул этот буфер! А во втором случае буфер был выплюнут до форка!!!

Вот:

/tmp/1.c                                                                                                                             137/137  KOI8-R       100%
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{

  printf("1234 ");
  fflush(stdout);
  fork();
  exit(0);
}

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от cdslow

Т.е. libc при старте начинает просматривать и открывать std-файлы (stdout,stderr,stdlog) и при открытии проверяет, а не tty ли файлик?
Если обнаруживает не-tty(в случае pipe) открывает файл как блочно-буферизированное, в случае tty(терминал) открывает как строчно-буферизированное?

drfaust ★★★★★
() автор топика
Ответ на: комментарий от Eddy_Em

Дошло: форкнутый процесс унаследовал stdout буфер и по завершению выплюнул этот буфер!

Причём криво-форкнутый. Может проскочить ситуёвина, когда «ребёнок» не успеет что-либо вывести, а «папаша» уже закончит свою жизнь через exit(0) и грохнет только-только родившегося «ребёночка» :)
Это был «слегка» перефразированный «тест яндекса», положение и применение fork сохранено :D

Данунафиг

Я приводил пример с «\n» загнанный в pipe:
./2 > 1 | cat 1
где выводятся обе строки.

drfaust ★★★★★
() автор топика
Последнее исправление: drfaust (всего исправлений: 2)
Ответ на: комментарий от drfaust

Ну так нужно ж демонизироваться "ребеночку", если папаша внезапно ласты склеить может... Не так это и сложно сделать ведь: позакрывал 1,2 и 3; открыл (если надо) вместо них /dev/null; заигнорировал SIG_HUP — вуаля!

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от drfaust

Ну, получается, что баш трубы буферизует посимвольно. Сам.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от cdslow

Понятно. Я никогда как-то об этом не задумывался, потому что перед fork всегда делал close(1);close(2);close(3)

А isatty использую — чтобы выхлоп изменять (на консольку идет цветной, а в файл или пайп — обычный, чтобы спецсимволами не засирать.

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Согласен.
Вот ещё одна идиотская математическая задачка от яндекса:
Дана функция на языке Python. Завершится ли когда-нибудь вызов dio()?Почему?

def dio():
       x = 1L
       while 1:
           for y in xrange(1, x):
             for z in xrange(1, y):
               if x*x == y*y + 12752041*z*z:
               return "Found it"
           x = x + 1

drfaust ★★★★★
() автор топика
Последнее исправление: drfaust (всего исправлений: 1)
Ответ на: комментарий от oneliner

Неправильно скопипастил - вот правильно:

def dio():
   x = 1L
   while 1:
       for y in xrange(1, x):
           for z in xrange(1, y):
               if x*x == y*y + 12752041*z*z:
                   return "Found it"
       x = x + 1
Тоже питон почти не знаю.

drfaust ★★★★★
() автор топика
Последнее исправление: drfaust (всего исправлений: 1)
Ответ на: комментарий от drfaust

Завершится ли когда-нибудь вызов dio()?Почему?

Судя по x = 1L, пытаются намекнуть на то, что xrange, работает только в диапазоне «коротких» чисел, а искомый ответ попадает в диапазон «длинных», поэтому найден никогда не будет.

Питон не знаю, считать лень :)

cdslow ★★
()
Ответ на: комментарий от drfaust

завершится если у уравнения x*x == y*y + 12752041*z*z есть решение

почему? потому что в питоне у лонга нет предела :)

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.