Well, a lot of stuff is going on here. I will try to explain it step by step.
When you start your terminal, the terminal creates a special file having path /dev/pts/<some number>
. Then it starts your shell (which is bash
in this case) and links the STDIN
, STDOUT
and STDERR
of the bash process to this special file. This file is called a special file because it doesn't actually exist on your hard disk. Instead, whatever you write
to this file, it goes directly to the terminal and the terminal renders it on the screen. (Similarly, whenever you try to read
from this file, the read
blocks until someone types something at the terminal).
Now when you launch your program by typing ./main
, bash calls the fork
function in order create a new process. The child process exec
s your executable file, while the parent process wait
s for the child to terminate. Your program then calls fork
twice and we have three processes trying to read their STDIN
s, ie the same file /dev/pts/something
. (Remember that calling fork
and exec
duplicates and preserves the file descriptors respectively).
The three processes are in race condition. When you enter something at the terminal, one of the three processes will receive it (99 out of 100 times it would be the parent process since the children have to do more work before reaching scanf
statement).
So, parent process prints the number and exits first. The bash process that was waiting for the parent to finish, resumes and puts the STDIN into a so called "non-canonical" mode
, and calls read
in order to read the next command. Now again, three processes (Child1, Child2 and bash) are trying to read STDIN.
Since the children are trying to read STDIN for a longer time, the next time you enter something it will be received by one of the children, rather than bash. So you think of typing, say, 23
. But oops! Just after you press the 2
key, you get Your number is: 2
. You didn't even press the Enter key! That happened because of this so called "non-canonical" mode. I won't be going into what and why is that. But for now, to make things easier, use can run your program on sh
instead of bash
, since sh
doesn't put STDIN into non-canonical mode. That will make the picture clear.
TL;DR
No, parent process closing its STDIN doesn't mean that its children or other process won't be able to use it.
The strange behavior you are seeing is because when the parent exits, bash
puts the pty (pseudo terminal) into non-canonical mode. If you use sh
instead, you won't see that behavior. Read up on pseudo terminals, and line discipline if you want to have a clear understading.
The shell process will resume as soon as the parent exits.
If you use wait
to ensure that parents exits last, you won't have any problem, since the shell won't be able to run along with your program.
Normally, bash makes sure that no two foreground processes read from STDIN simultaneously, so you don't see this strange behavior. It does this by either piping STDOUT of one program to another, or by making one process a background process.
Trivia: When a background process tries to read from its STDIN
, it is sent a signal SIGTTIN
, which stops the process. Though, that's not really relevant to this scenario.