C - Creating child processes - c

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.

Related

C: Multi process CMD does nothing after running all commands

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.

Unix command line arguments to kill process after a single print

I need to pass unix arguments to run C file so that it prints a certain line "Hello World" a single time only. The file uses fork to print the sentence multiple times but I need to send a kill signal to kill the processes after the sentence "Hello World" is printed once only.
I tried
./"file name" sleep 4 KILL -9
I do not think I am using the right syntax here.
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
int m, i, c = 0;
pid_t pgid;
m = atoi(argv[1]);
for(i = 0; i < 3; ++i)
{
if(fork() > 0)
{
c = 1;
}
}
if(!c)
{
pgid = getpgid(getpid());
setpgid(getpid(), getpid());
kill(m * pgid, SIGINT);
}
sleep(3);
if(fork() > 0)
{
puts("Hello World");
}
return 0;
}
It is printing few times and then it hangs.

How to display child processes using pstree in C

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.

C - fork() & execl() & loop + "half pyramid output"

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.

Using pipes to implement simple shell in c? [duplicate]

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.

Resources