Reputation: 394
I am using fork and the child process reads data ten times from user using a scanf inside the for loop. The parent process however sends the SIGSTOP signal to child after 4 seconds of sleep and reads a value from the user and prints it. But if the user has entered data but not pressed enter for the scanf in the child process the parent process reads but prints the data written in the child process. How do I stop this from happeneing.
ch=fork();
if(ch==0)
{
for(i=0;i<10;i++)
{
fflush(stdin);
scanf("%s",buf);
printf("%d: %s\n",i,buf);
}
}
else
{
char buf2[100],cha;
sleep(4);
kill(ch,SIGSTOP);
write(STDOUT_FILENO,"\nchld stopped\n",14);
memset(stdin,0,sizeof(stdin));
read(STDIN_FILENO,buf2,2);
write(STDOUT_FILENO,buf2,2);
kill(ch,SIGCONT);
wait(SIGCHLD);
}
So the output for example comes like this:
a
0: a
b
1: b
ac (I dont press enter here and wait for SIGSTOP)
chld stopped
tr (Entered data for parent and pressed enter)
ac2: tr
c
3: c ... and so on
So after entering tr why does my parent display ac?
Upvotes: 0
Views: 295
Reputation: 53
It is because of read(), write() function. When you input something without pressing enter. It will be in stdinput, whatever in stdinput, it will read by read() function store in buf2 as specified in your example. And whatever in buf2, it will send to stdoutput by write(). You can see the difference when you comment read(), write() function, or just print "buf2".
Upvotes: 0
Reputation: 394
Okay I found the solution.
I used tcflush(): flush non-transmitted output data, non-read input data, or both.
tcflush(STDIN_FILENO,TCIFLUSH); line just before the read in the parent did it.
I found the solution here... How can I flush unread data from a tty input queue on a UNIX system?
Upvotes: 1
Reputation:
fflush(stdin)
is never the right thing to do, although lots of people have tried it. fflush
is only for output. Your memset
is pure insanity. The argument to wait
isn't supposed a signal number - it's not even the right type, so you should have got a warning which you apparently ignored.
Those are the easy errors. There is a deeper conceptual problems with what you're trying to do.
Since you didn't modify any tty settings, the tty is in canonical mode while your program is running. That means the tty handles line editing (backspace, Ctrl-U, Ctrl-W, etc.) and doesn't send anything to the program until the line is terminated.
When you have typed a partial line, that partial line is not in the stdin buffer. It's in the tty buffer. It doesn't belong to any process yet. That's why your parent process can read a line that was partially typed while the child was attempting to read. The child never got any of it.
To empty the tty buffer, this should work: turn off canonical mode; set non-blocking mode; read into a until an error occurs (EAGAIN/EWOULDBLOCK will happen in non-blocking mode when the tty has nothing left to give you); turn blocking and canonical mode back on. The idea is to consume whatever is currently available without waiting for more. Code to perform the individual steps should be easy to find.
In general, I question the wisdom of an interface that offers the user an opportunity to enter information, then spontaneously interrupts the reading of that information to read something else. It's going to cause users to shout at the secondary input prompt: HEY! I'M TYPING HERE!
Upvotes: 2