quick question I was asked about create a program in which one process generates 32 child processes. I created below program(is it correct ?), but do you know how can I using the pstree command, present the tree of these processes ? Appreciate any help.
#int main()
{
for(int i = 0; i < 32; ++i)
{
if(fork() == 0)
{
sleep(5);
return 0;
}
}
for(int i = 0; i < 32; ++i)
{
waitpid(-1, NULL, 0);
}
return 0;
}:
For me this works after adding a few #include lines, like this:
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
for(int i = 0; i < 32; ++i) {
if(fork() == 0) {
sleep(30);
return 0;
}
}
for(int i = 0; i < 32; ++i)
waitpid(-1, NULL, 0);
return 0;
}
Then I can compile:
gcc pp.c -o myprog
which generates the myprog executable. Then I run that, and while it is running I can open another terminal window and run pstree there, then it shows the parent process and the 32 child processes, it looks something like this:
systemd-+-[...]
|-[...other stuff...]
|-systemd-+-(sd-pam)
| |-[...other stuff...]
| |-gnome-terminal--+-bash---myprog---32*[myprog]
| | |-bash---pstree
| | `-4*[{gnome-terminal-}]
| |-[...other stuff...]
I guess the bash---myprog---32*[myprog] part there means that the myprog process created 32 child myprog processes, so it seems to work as expected.
Related
I made this in C, and it does run all commands concurrently. But at the end, it puts the last command in the user input part of the CMD then does nothing right after.
This is the output of the command:
hen03:~/Lab_08> ./assign8 whoami , ls -a , pwd
Child Process: PID=11895, PPID=11894, Command=whoami
Child Process: PID=11897, PPID=11894, Command=pwd
Child Process: PID=11896, PPID=11894, Command=ls
/home/uid454/Lab_08
hen03:~/Lab_08> . .. assign8 assign8.c makefile uid454.zip
uid454
hen03:~/Lab_08>
And this is the code I wrote
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
void startProcesses(int commands, char *commandList[6][100]){
static pid_t forks[6];
int status[6];
int i;
for(i = 0; i < commands; i++){
switch(forks[i] = fork()){
case -1: //failed
perror("fork failed");
break;
case 0: //child does things
printf("Child Process: PID=%ld, PPID=%ld, Command=%s\n", (long) getpid(), (long) getppid(), commandList[i][0]);
if(execvp(commandList[i][0], commandList[i]) < 0){
printf("something failed\n");
}
break;
default:
if(i == commands-1){
waitpid(forks[i], &status[i], 0);
}
}
}
}
int main(int argc, char *argv[])
{
int commandNum = 0, index, numOfCommands = 1, j =0;
static char *commandList[6][100];
//start of separate algo
for (index = 1; index < argc; index++){
if(strcmp(strtok(argv[index], " "), ",") == 0){
commandNum++;
numOfCommands++;
commandList[commandNum-1][j] = NULL;
j = 0;
continue;
}
else{
commandList[commandNum][j] = argv[index];
j++;
}
}
//end of separation algo
startProcesses(numOfCommands, commandList);
return 0;
}
I honestly have no idea what the problem is nor how to even google it for that matter. Could someone explain why its doing this?
edit: took out line numbers
Is the problem that the output of some child-processes are shown tacked on to the shell prompt?
Then that's because you don't wait for all your child processes, only the last one. And there's no guarantee that the child-processes will execute in any specific order.
That means your parent process could exit before all child-processes have finished, which means that the shell is back in control and will display the prompt.
You should really wait for all child-processes. Preferably in a second loop if you want the child-processes to run in parallel.
cmds is a list of commands to call. In my case, I'm tring to call ls | grep c. When I run the program, nothing gets printed. It seems grep is waiting for something?
Note: If I only use ls (via execPipe(cmds,1)), everything works.
What is wrong?
int execPipe(char*** cmds,int len){
int i;
int pipefd[100][2];
for(i = 0; i < len; i++)
pipe(pipefd[i]);
i = 0;
for(i = 0; i < len; i++){
if (fork() == 0){
printf("executing #%d %s\n",i,cmds[i][0]);
//i=0: in=sdtin, out=1
//i=1: in=1,out=3
//i=2: in=3,out=5
//i=len in=len*2-1, out=sdtout
close(pipefd[i][0]);
if(i != 0){
dup2(pipefd[i-1][1],0); //read becomes the write of last one
}
if(i != len-1){
dup2(pipefd[i][1],1); //write becomes pipefd[i][1]
}
execvp(cmds[i][0],cmds[i]);
return EXIT_SUCCESS;
}
close(pipefd[i][0]);
close(pipefd[i][1]);
wait(NULL);
}
return 0;
}
int main(){
char*** cmds = malloc(2*sizeof(char**));
cmds[0] = malloc(2*sizeof(char**));
cmds[0][0] = "ls";
cmds[0][1] = NULL;
cmds[1] = malloc(3*sizeof(char**));
cmds[1][0] = "grep";
cmds[1][1] = "c";
cmds[1][2] = NULL;
execPipe(cmds,2);
return 0;
}
This code works:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static
int execPipe(char ***cmds, int len)
{
int i;
int pids[len];
int pipefd[len][2];
for (i = 0; i < len - 1; i++)
pipe(pipefd[i]);
for (i = 0; i < len; i++)
{
int pid;
if ((pid = fork()) == 0)
{
printf("PID %d: executing #%d %s\n", (int)getpid(), i, cmds[i][0]);
if (i != 0)
{
dup2(pipefd[i - 1][0], 0); // JL: Fix
}
if (i != len - 1)
{
dup2(pipefd[i][1], 1); // write becomes pipefd[i][1]
}
for (int j = 0; j < len - 1; j++) // JL: Fix
{
close(pipefd[j][0]);
close(pipefd[j][1]);
}
execvp(cmds[i][0], cmds[i]);
fprintf(stderr, "Failed to execute command %s\n", cmds[i][0]);
return EXIT_FAILURE;
}
else if (pid < 0)
{
fprintf(stderr, "failed to fork for %s\n", cmds[i][0]);
exit(1);
}
else
pids[i] = pid;
}
for (i = 0; i < len - 1; i++) // JL: Fix
{
close(pipefd[i][0]);
close(pipefd[i][1]);
}
int corpse;
int status;
int kids = len;
while (kids > 0 && (corpse = wait(&status)) > 0)
{
printf("PID %d died with status 0x%.4X\n", corpse, status);
for (i = 0; i < kids; i++)
{
if (pids[i] == corpse)
{
pids[i] = pids[kids-1];
kids--;
break;
}
}
}
return 0;
}
int main(void)
{
char ***cmds = malloc(2 * sizeof(char **));
cmds[0] = malloc(2 * sizeof(char **));
cmds[0][0] = "ls";
cmds[0][1] = NULL;
cmds[1] = malloc(3 * sizeof(char **));
cmds[1][0] = "grep";
cmds[1][1] = "c";
cmds[1][2] = NULL;
execPipe(cmds, 2);
return 0;
}
Comments:
Notice how many close operations there are.
It would be reasonable to factor the close loop into a function that gets called where needed.
You could get away without the first child closing the pipes, but it is silly to break the symmetry.
It is crucial that the parent close the pipes — but only after the pipes are finished with (that is, after all the children are created).
The wait() loop deals with the situation where the parent process had children that it didn't know about that terminate before the children it launches — a rather unusual but far from impossible circumstance. It would be possible simply to wait until all children die, but maybe one of the previously created children isn't going to terminate. The loop waits until all the known children have died and then exits.
A more complex mechanism would only have two pipes open at any one time, even in a 50 process pipeline, rather than opening all 49 pipes at once, but that's a refinement for later.
You should extend this to a 3-process or longer pipeline and check that it works. Possible pipelines include:
who | awk '{print $1}' | sort
who | awk '{print $1}' | sort | uniq -c
who | awk '{print $1}' | sort | uniq -c | sort -n
Beware: the shell removes single quotes.
I have a troubles with the following. Let's say, I have a two programs, one is "input.c" and second is "output.c". Output is a simple one and looks like this (I will paste only the most important passage).
outputbin.c
//
char buffer[512];
strncpy(buffer, argv[1], sizeof(buffer));
printf("Your output is: %s\n", buffer);
//
And this is the main passage from my input.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid;
char *charchar = "\x41";
int status;
char *outputbin;
int i, j, iterations;
if(argc < 2)
{
fprintf(stderr, "Usage: %s <iterations> <outputbin>\n", argv[0]);
exit(0);
}
iterations = atoi(argv[1]);
outputbin = argv[2];
pid = fork();
if(pid != 0)
{
waitpid(-1, &status, 0);
}
if(pid == 0)
{
for(i=0; i < iterations; ++i)
{
for(j = 0; j <= i; ++j)
{
printf("%s", charchar);
//execl(outputbin, outputbin, charchar, NULL);
}
printf("\n");
}
}
return 0;
}
When I compile this program using gcc and do this (without argv[2]):
./input 10
I get this:
A
AA
AAA
AAAA
AAAAA
AAAAAA
AAAAAAA
AAAAAAAA
AAAAAAAAA
AAAAAAAAAA
It's okay, but only till I remove this piece of code - "printf("%s", input);" and uncomment "execl", so:
for(j = 0; j <= i; ++j)
{
execl(output, output, input, NULL);
}
And run: ./a.out 10 ./outputbin
I get only this - Your output is: A
Only first char and that's all. How to let is execute whole "half pyramid" of strings line by line? No matter what I tried, everything end with the same result.
Assuming it executes successfully, execl does not return - it replaces the program running in the process with another program. So when calling:
for(j = 0; j <= i; ++j)
{
execl(output, output, input, NULL);
}
The loop will only iterate one time - after execl is called, outputbin will start executing. If you want to keep the loop logic, you should move it to outputbin.c so that it'll be executed there.
How do i create a number of child processes given from command line ?
Something like this , where n is given from command line :
for (i = 0; i < n; i++) {
pids[i] = fork();
}
No, this will not work because then the child processes will create more children and this will not be what you wanted. For a better idea of how that happens, go take a look at fork() branches more than expected?. So you have to break out of the loop if the current process is a child like so:
for (i = 0; i < n; i++) {
if (!(pid[i] = fork()))
break;
}
In order to see this in action, lets look at minimally complete example
file.c:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i, n = atoi(argv[1]);
pid_t *pid = calloc(n, sizeof *pid);
for (i = 0; i < n; i++)
if (!(pid[i] = fork()))
break;
puts("hello world");
return 0;
}
Then compile and run it
$ gcc -o file file.c
$ ./file 3
hello world
hello world
hello world
hello world
Note that there are 4 messages because there 3 children plus the parent process.
This question already has answers here:
Pipe implementation
(2 answers)
C Minishell Adding Pipelines
(1 answer)
Closed 8 years ago.
I am building a simple shell in c using fork and execlp. I will be given a set of commands separated by pipes. eg: ls -l | wc -l .
I want to use pipes for intra process communication. So the output from ls -l is input for wc -l. There can any number of commands separated by pipes. I am not understanding whether to create a pipe between a child process and parent and then when I get a output from a child process somehow transfer that output to another child process... I have parsed the inputs. How can I go about this?
void excueteCommands() {
int i, j;
int fd[2];
int cid1;
commandNode* ptr = head;
while (ptr != NULL) {
for (i = 0; i <= pipeCount; i++) {
cid1 = fork();
if (!cid1) {
if (i != 0) {
dup2(fd[i - 1][0], 0);
}
if (i != pipeCount) {
dup2(fd[i][1], 1);
}
for (j = 0; j < pipeCount; j++) {
close(fd[j][0]);
close(fd[j][1]);
}
execlp(ptr->command, ptr->args, NULL);
exit(0);
}
ptr = ptr->next;
}
}
for (i = 0; i < pipeCount; i++) {
close(fd[i][0]);
close(fd[i][1]);
}
}
I also had same assignment last year. Your need not to handle input and output from one process to another separately. Just initialize pipes between the series of processes and the flow of input and output would take place itself. You only need to give input to first command and take output from the last command.
Following is code snippet I used.
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <unistd.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <sys/wait.h>
int exit_flag = 0;
#define ARG_SIZE 100
int main ()
{
int size = 1000,i,j;
int pipe_count = 0;
int fd[100][2],cid1,cid2,length,status;
char string[][100] = {"ls","wc"};
pipe_count = 1;
if(pipe_count)
{
for(i = 0;i < pipe_count;i++)
{
pipe(fd[i]);
}
for(i = 0;i <= pipe_count;i++)
{
cid1 = fork();
if(!cid1)
{
if(i!=0)
{
dup2(fd[i-1][0],0);
}
if(i!=pipe_count)
{
dup2(fd[i][1],1);
}
for(j = 0;j < pipe_count;j++)
{
close(fd[j][0]);
close(fd[j][1]);
}
execlp(string[i], string[i], NULL);
exit(0);
}
}
for(i = 0;i < pipe_count;i++)
{
close(fd[i][0]);
close(fd[i][1]);
}
waitpid(cid1,&status,0);
}
else
{
execlp(string[0], string[0], NULL);
}
return 0;
}
In above code string[] array contains all commands separated by '|' in sequence. fd[][2] is array of file descriptors. fd[i][0] is input of i+1 command and fd[i][1] is output of ith command. So output of i goes to input of i+1 using fd[i] pipe.
I don't remember now how the dup2 and close commands were handled. May you may get them since you have done them recently. I there is any doubt then I would try my best to clarify.