How do fork () and scanf () work?

I tried to understand what would happen if I read something from the keyboard, while I have several processes with fork () (in my case there are two children and a parent), and I found the following problem: I need to say parents to wait for children to process, otherwise the program behaves strangely.
I did a study and I found that the problem is with the parent, he needs to wait for the child process to complete, because if the parent process ends first, it closes STDIN, am I right? But also I found that every process has a copy of STDIN, so my question is:

Why it works this way, and why only the parent has a problem with STDIN, but the children don’t, I mean why, if the child process ends first, it does not affect STDIN, but if the parent process ends first, it affects STDIN ?

  • Here are my tests:

    • I started the program without wait (), and after I dialed a number that stopped the program, but then I pressed enter two more times, and two other messages from printf () appeared. Here is the picture.

    • When I ran the program with wait (), everything worked fine, each process named scanf () separately and read a different number. Here is the picture.

+5
source share
2 answers

Well, there are a lot of things. I will try to explain this step by step.


When starting the terminal, the terminal creates a special file with the path /dev/pts/<some number> . Then it launches your shell (which in this case is bash ) and associates the STDIN , STDOUT and STDERR the bash process with this special file. This file is called a special file because it does not actually exist on your hard drive. Instead, no matter what you write for this file, it goes directly to the terminal, and the terminal displays it on the screen. (Similarly, whenever you try to read from this file, read blocks until someone types something on the terminal).

Now, when you run your program by typing ./main , bash calls the fork function to create a new process. The child process exec is an executable file, and the parent process, wait is for shutting down the child process. Then your program calls fork twice, and we have three processes trying to read their STDIN s, that is, the same file /dev/pts/something . (Remember that calling fork and exec duplicates and saves the file descriptors accordingly).

Three processes are in a race state. When you enter something on the terminal, one of the three processes will receive it (99 out of 100 times it will be the parent process, since children have to do more work before reaching the scanf instruction).

So, the parent process prints the number and exits first. The bash process, which expected the parent to finish, resumes and puts the STDIN into a so called "non-canonical" mode , and calls read to read the next command. Now again, three processes (Child1, Child2, and bash) are trying to read STDIN.

As children try to read STDIN for a longer time, the next time you enter something, it will be adopted by one of the children, not bash. So you are thinking of typing, say, 23 . But oops! As soon as you press 2 , you will get Your number is: 2 . You didn’t even press Enter! This was due to this so-called "non-canonical" regime. I will not go into what and why. But now, to simplify the task, use the sh program instead of bash , since sh does not put STDIN in noncanonical mode. This will make the image clear.


TL DR

  • No, the parent process closing it with STDIN does not mean that its children or another process will not be able to use it.

  • The strange behavior you see is due to the fact that when a parent exits, bash puts pty (pseudo-terminal) in non-canonical mode. If you use sh , you will not see this behavior. Read pseudo-terminals and linear discipline if you want a clear understanding.

  • The shell process will resume after the parent exits.

  • If you use wait to ensure that parents leave last, you will not have any problems, since the shell will not be able to work with your program.

  • Usually bash ensures that two foreground processes are not read from STDIN at the same time, so you do not see this strange behavior. It does this by either sending the STDOUT of one program to another, or by creating one process of a background process.

    General information. When the background process tries to read its STDIN , it sends a SIGTTIN signal, which stops the process. Although, this is not particularly relevant to this scenario.

+6
source

There are several problems that can occur when multiple processes attempt to perform I / O on the same TTY. Without code, we cannot say what could happen.

  • An attempt to input / output from a background process group may send a signal: SIGTTIN for input (usually enabled) or SIGTTOU for output (usually disabled)

  • Buffering: if you do any I / O before the plug, any data that has been buffered will be available for both processes. Under some conditions, using fflush may help, but it's better to avoid buffering entirely. Remember that, unlike output buffering, it is not possible to buffer input in stages (although you can only buffer what is available, so it can be buffered by line first).

  • Race conditions: if several processes try to read the same file in the form of a pipe, it is undefined, which will β€œwin” and actually receive an input every time it is available.

+1
source

Source: https://habr.com/ru/post/1261954/


All Articles