In bash, when I type ls and hit enter, the binary ls will run and I will return to shell prompt again without doing anything from my side.
However this program, written in C will block:
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
pid_t other = fork();
// other will be 0 for the child process
// other will be the childs process' value in the parent process.
switch(other) {
case 0:
printf("%s %i\n", "I am the child process!", other);
execl("/bin/ls","ls",NULL);
return 0;
default:
printf("%s %i\n", "I am the parent process!", other);
return 1;
}
}
Why?
The output is as follows:
Korays-MacBook-Pro:~ koraytugay$ ./a.out
I am the parent process! 40309
I am the child process! 0
Korays-MacBook-Pro:~ koraytugay$ AndroidStudioProjects Movies happyko koray.i
Applications Music hello.c koray.o
ClionProjects Pictures hello.sh koray.s
Code Public innbound mssql
Desktop TheElementsFiles innbound-pf nono.txt
Documents VirtualBox VMs innbound_usage.log svn-key
Downloads a.out k.txt tugay.c
IdeaProjects asm.asm klinnck webtoolkit
Koray.class asm.hack klinnck-pf
Koray.java cexamples koray.a
Library fifa.sql koray.c
At this point I will need to hit Enter so that I return to bash prompt. Why?
At this point I will need to hit ENTER so that I return to bash prompt.
Actually, you're already back to the prompt, you just did not realize it.
To elaborate, the problem you facing here is, the parent does not wait for the child to exit and returns beforehand the child finishes execution. So, the shell prompt comes back, and then the output from the chlid process (output of ls) gets printed on the output.
If you notice properly, You've already got the prompt back, and your output appears later.
Korays-MacBook-Pro:~ koraytugay$ ./a.out
I am the parent process! 40309
I am the child process! 0
****Korays-MacBook-Pro:~ koraytugay$***** AndroidStudioProjects Movies happyko koray.i
Applications Music hello.c koray.o
ClionProjects Pictures hello.sh koray.s
Code Public innbound mssql
Desktop TheElementsFiles innbound-p
Above, please note the **** marked line. There, you got your shell prompt back.
At this point I will need to hit Enter so that I return to bash.
Except no, you're already in bash. But all that ls output after the prompt makes it seem that you are not. Go ahead, try another command.
Related
So I have this simple program that sleeps for 4 second if the value returned by fork is '0' meaning that the child process is executing, I've tried using sleep in child process but the program is blocked, and flushing standard output isn't working...
code:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
pid_t value = fork();
if (value == 0) {
sleep(4);
}
printf("Value returned by fork: %d\n", value);
printf("I'm the process N°%d\n", getpid());
return 0;
}
I'm running on Ubuntu 20.04.3 LTS.
Output:
Value returned by fork: 12618
I'm the process N°12617\
farouk#farouk-HP-Pavilion-Desktop-TP01-1xxx:~/sysexp$ Value returned by fork: 0
I'm the process N°12618
To allow this question to have an accepted answer.
The child process is not blocking the shell. The shell gave its prompt and the child wrote some output after the prompt, leaving the cursor at the start of a line without a shell prompt visible — because the shell prompt already appeared earlier.
There are a variety of ways around this.
The simplest is just to type a command such as ps and hit return, noting that the shell executes it, and that the ps output does not list the child process. If you type the ps command quick enough, you might see the child listed in the output before its output appears.
Another is to modify the program so that it waits for all child processes to exit before it exits — using wait() or waitpid(). The same code can be used in the child and the parent since the child will have no children of its own. The call to the wait function will return immediately with a 'no more children' status (error).
You can find extensive discussion of all this in the comments — I've chosen to make this a Community Wiki answer since there was a lot of activity in the comments that identified the gist of this answer.
In my homework I should explain what is happening in the following code:
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
int x = 1;
if(fork() == 0){// child
printf("printf1: x=%d\n", ++x);// add then print
}
printf("printf2: x=%d\n", --x);
exit(0);
}
It's pretty straightforward and easy to understand. Most of the time I get the following output:
printf2: x=0
printf1: x=2
printf2: x=1
This means that the parent process was completed before the child and the child became a zombie process.
But sometimes I get the following output:
printf1: x=2
printf2: x=1
After printing that the program freezes (It does not print anything and does not stop).
I am running the program on Ubuntu.
Any explanation will be appreciated.
You have 3 processes writing to your terminal: parent, child and the shell interpreter. The parent process and the shell have "syncronized" output, but the child process may interleave its output with either of those. What you may perceive as a hanged process, may actually only be mangled output.
When you think it has hanged, you may try to enter a command and press enter...
I'm having trouble understanding how to do basic piping in C. I looked at a couple other questions on this topic, and either they were for subtly different issues, or I'm so far off the mark on this subject I couldn't understand why the answers are good for my problem.
This program below is just a simple test I made, where I'm trying to get behaviour equivalent to typing "ls | grep a" into my shell. (I have a homework assignment where I have to build a shell that can handle piping, but this is my first step towards understanding pipes to even attempt the homework). I get the correct output, but the terminal prompt ends up appearing before the output, making it look like it did not properly terminate. Since this is connected to a shell homework, I'm worried that will impact the grade (and it just feels wrong to let it look like that anyway). Any advice?
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
int main()
{
int fdpipe[2];
pipe(fdpipe);
int f1 = fork();
if(f1 == 0)
{
close(fdpipe[1]);
dup2(fdpipe[0],0);
close(fdpipe[0]);
execlp("/bin/grep","grep","a",NULL);
}
else
{
close(fdpipe[0]);
dup2(fdpipe[1],1);
close(fdpipe[1]);
execlp("/bin/ls","ls",NULL);
wait(NULL);
}
return 0;
}
Here's an example of my terminal output.
1067: ls
a.out test.c test.cc
NathanE: ~/Desktop/playground
1068: ./a.out
NathanE: ~/Desktop/playground
1069: a.out
(The beginning of this line is where my cursor is)
What I'm expecting would be:
1067: ls
a.out test.c test.cc
NathanE: ~/Desktop/playground
1068: ./a.out
a.out
NathanE: ~/Desktop/playground
1069: (my cursor would go here)
The child process runs grep, while the parent replaces itself with ls. The wait(NULL) does nothing, because successful exec*() never return.
Because the control returns to the shell immediately after ls completes, the shell can display the next prompt before grep completes.
There are two approaches you can use to avoid this:
fork() both child processes, and wait() for them
Replace the process itself with the last process in the pipe chain
Either will ensure that control is returned to the shell only after the last process in the pipe chain completes.
In my C program, I want to have different behavior whether my process (POSIX) is running in the background or in the foreground. I don't have access to argc/argv.
I was thinking about something in the likes of:
if (isatty(0)) {
printf("Foreground\n");
} else {
printf("Background\n");
}
But this isn't working well for me. I get the following result:
$ ./myprog &
Foreground
The man page of isatty() clearly indicates that the function test whether a file descriptor refers to a terminal. When you pass '0' as a argument, it mostly refers to STDIN, so isatty() will always return TRUE, that means you code behaves like
if (TRUE) {
printf("Foreground\n");
} else {
printf("Background\n");
}
As indicated by the comments, the correct way to check foreground vs background process is like this code
#include <unistd.h>
#include <stdio.h>
int main()
{
pid_t console_pid = tcgetpgrp(STDOUT_FILENO);
pid_t my_pid = getpgrp();
if(console_pid == my_pid)
printf("process foregrounded\n");
else
printf("process backgrounded\n");
return 0;
}
Here is the output on my ubuntu machine
ubuntu#4w28n62:~$ ./a.out
process foregrounded
ubuntu#4w28n62:~$ ./a.out &
[1] 4814
ubuntu#4w28n62:~$ process backgrounded
[1]+ Done ./a.out
I have the following code:
for (loop=0;loop<2;loop++)
{
child_pid = fork();
if (child_pid == 0)
{
rc = execvp ("/usr/local/some_program", arguments);
}
}
I change the arguments passed to /usr/local/some_program based on the value of loop. I want the some_program to parallel-ly execute two instances. But i see that i first execute some_program once and only after it finishes that i get execute the second instance of some_program.
I not able to get them to run parallelly and independently.
Instead of fork, should i use pthreads?
The some_program that i am trying to execute is completely unrelated to the parent process.
Thanks
"I not able to get them to run parallelly and independently." - No. Both process will be executed in parallel. To check that create two programs like this-
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
printf("Pid= %d\n", getpid());
while(1);
}
Compile those 2 program's and make two executable files. Pass these 2 exe file names via command line arguments to main program and run that using system command.But your main program should be live.
for (loop=0;loop<2;loop++)
{
child_pid = fork();
if (child_pid == 0)
{
system(argv[loop+1]);
exit(0); // if you don't use exit your second exe file will be executed twice.
}
}
while(1);
Now type ps command in terminal and find the TTY name and run the main program. Open a new terminal and type
ps -e | grep pts/X // pts/X is main program running terminal name. it may pts/0 or pts/1 ...
Through this you can come to know that the two processes running parallelly or not.