Run N concurrent processes in C - c

I am trying to run N concurrent processes in a C program. I've built a simple example that takes commands as arguments, creates a fork for each one, and executes it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
int status;
waitpid(pid, &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
}
else
{
char cmd[1024];
sprintf(cmd, "%s", argv[i], i);
system(cmd);
_exit(1);
}
}
printf("Finished\n");
return 0;
}
This seems to run the processes correctly, but not concurrently. Any ideas as to what am I doing wrong?
EDIT: I've edited based on suggestions, but this also does not seem to work.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int i;
pid_t *pids = malloc( sizeof(pid_t) * (argc) );
int *statuses = malloc( sizeof(int) * (argc) );
for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid < 0)
{
fprintf(stderr, "forking error\n");
exit(1);
}
else if(pid > 0)
{
//int status;
//waitpid(pid, &status, 0);
//printf("Command %s has completed successfully by PID=%d\n", argv[i], pid);
pids[i] = pid;
}
else
{
char cmd[1024];
sprintf(cmd, "%s > out.%d", argv[i], i);
system(cmd);
_exit(1);
}
}
int needtowait = 0;
do
{
needtowait = 0;
for(i = 1; i < argc; i++)
{
if(pids[i] > 0)
{
if(waitpid(pids[i], &statuses[i], 0) != 0)
{
pids[i] = 0;
char *successstr = "successfully";
if(statuses[i])
{
successstr = "unsuccessfully";
}
printf("Command %s has completed %s by PID=%d\n", argv[i], successstr, pids[i]);
}
}
else
{
needtowait = 1;
}
sleep(0);
}
} while(needtowait);
printf("Finished!\n");
return 0;
}

The reason you are not running these processes concurrently is in this line:
waitpid(pid, &status, 0);
The main process that forks out the child process waits for the child process to exit before continuing with the loop, and starting the next process.
Since you want to run your processes concurrently, you can do this: allocate an array of pid_t for process IDs, and fill it in inside the loop. Once you are out of the loop, you can wait for the individual processes to complete by executing waitpid calls in a loop.
pid_t *pids = malloc(argc * sizeof(pid_t));
for (int i = 0 ; i < argc ; i++) { // Start i at 0, not at 1
pid_t pid = fork();
if (pid < 0) {
...
} else if (pid > 0) {
pids[i] = pid;
} else {
char cmd[1024];
sprintf(cmd, "%s", argv[i+1], i+1);
system(cmd);
_exit(1);
}
}
for (int i = 0 ; i < argc ; i++) {
int status;
waitpid(pids[i], &status, 0);
printf("Command %s has completed successfully by PID=%d\n", argv[i+1], pids[i]);
}

Sure. Your parent process is waiting for the child process to finish executing before forking again. You're just running cmd sequentially N times.

Related

Controlling processes execution using signals

I was given this particular task:
Using SIGCONT, SIGSTOP, and SIGCHLD, write a program that accepts
through argv[] a list of commands (none of them has arguments) and
runs the commands in a round-robin style, alternating commands in
1-second intervals.
To achieve it, I tried this:
int dead_children = 0;
int nr_processes;
void inc_dead () {
printf("I, %d, died\n", getpid());
dead_children++;
if (dead_children == nr_processes)
_exit(0);
}
int main (int argc, char *argv[]) {
int pids[argc - 1];
nr_processes = argc - 1;
signal(SIGCHLD, inc_dead);
for (int i = 1; i < argc; i++) {
pid_t pid;
if ( (pid = fork()) == -1 ) {
perror("fork");
return EXIT_FAILURE;
}
if ( !pid ) {
pause();
execlp(argv[i], argv[i], (char *) NULL);
perror("exec");
_exit(1);
}
pids[i - 1] = pid;
}
while (dead_children < nr_processes)
for (int j = 0; j < argc - 1; j++) {
kill(pids[j], SIGCONT);
sleep(1);
kill(pids[j], SIGSTOP);
}
return EXIT_SUCCESS;
}
I tried to run this code with very simple program that would allow me to verify task's correctness:
int main (void) {
int i = 5;
while (i-- > 0) {
printf("This is %d saying HI!\n", getpid());
sleep(1);
}
return EXIT_SUCCESS;
}
However, this does not work. I noticed that after creation, child processes never left pause() instruction, even though parent is sending a SIGCONT. Any thoughts on how to achieve the goal?

Is it possible for a child process to get the PID of its siblings?

The child process is another C program run with execlp. The machine is Unix. I know the child process can access the process table with execlp("ps", "ps", NULL) but I can't figure out how it can determine its sibling.
Even though the processes are asynchronous, I know that the sibling process will be running.
Is it possible for a child process to get the PID of its siblings?
Without talking with the parent using sort of a protocol, this is not possible in a portable manner. On some systems it might not even be possible at all.
yes, it is possible. I am attaching c code for this. Here I have taken 4 children and all are sharing their pid's.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define NUM_CHILDREN 4
/* Entry point for the child processes */
int child_main(int pipe_read_end) {
pid_t my_pid = getpid();
/* Read child pids from pipe */
int child_pids[NUM_CHILDREN];
unsigned int bytes_read = 0;
while (bytes_read < sizeof(child_pids)) {
ssize_t result = read(pipe_read_end, ((unsigned char *) child_pids) + bytes_read, sizeof(child_pids) - bytes_read);
if (result < 0) {
perror("error reading from pipe");
return 1;
} else if (result == 0) {
fprintf(stderr, "unexpected end of file\n");
return 1;
} else {
bytes_read += result;
}
}
close(pipe_read_end);
/* Do something useful with these child pids */
for (int i = 0; i < NUM_CHILDREN; i++) {
printf("Child %d received sibling pid %d\n", my_pid, child_pids[i]);
}
return 0;
}
/* Entry point for the parent process. */
int main() {
int child_pids[NUM_CHILDREN];
int pipe_write_ends[NUM_CHILDREN];
for (int i = 0; i < NUM_CHILDREN; i++) {
/* Create the pipe for child i */
int pipefd[2];
if (pipe(pipefd)) {
perror("error creating pipe");
return 1;
}
int pipe_read_end = pipefd[0];
int pipe_write_end = pipefd[1];
/* Fork child i */
pid_t child_pid = fork();
if (child_pid < 0) {
perror("error forking");
return 1;
} else if (child_pid == 0) {
printf("Child %d was forked\n", getpid());
close(pipe_write_end);
return child_main(pipe_read_end);
} else {
printf("Parent forked child %d\n", child_pid);
close(pipe_read_end);
pipe_write_ends[i] = pipe_write_end;
child_pids[i] = child_pid;
}
}
/* Send pids down the pipes for each child */
for (int i = 0; i < NUM_CHILDREN; i++) {
unsigned int bytes_written = 0;
while (bytes_written < sizeof(child_pids)) {
ssize_t result = write(pipe_write_ends[i], ((unsigned char *) child_pids) + bytes_written, sizeof(child_pids) - bytes_written);
if (result < 0) {
perror("error writing to pipe");
return 1;
} else {
bytes_written += result;
}
}
close(pipe_write_ends[i]);
}
/* Wait for children to exit */
for (int i = 0; i < NUM_CHILDREN; i++) {
if (waitpid(child_pids[i], 0, 0) < 0) {
perror("error waiting for child");
return 1;
}
}
}

C fork and pipe printing pid in order

So I need this program which needs to create argv[1] child using fork() and print what children number are they and what PID do they have in order of its creation.
I have to do that using pipes blocking properties.
Example output:
I am child 1 and my PID is 25853.
I am child 2 and my PID is 25854.
I am child 3 and my PID is 25855.
This is what I have tried so far, but it doesn't respect the order of children creation.
int main(int argc, char* argv[])
{
char buffer[80];
int p[2], i;
int pid = getpid();
for (i = 0; i < atoi(argv[1]); i++) {
pipe(p);
if (fork() == 0) {
read(p[0], &pid, sizeof(pid)); // It should block here until there's
// something in the pipe to read
sprintf(buffer, "I am child %d and my PID is %d\n", i + 1, getpid());
write(1, &buffer, strlen(buffer));
close(p[0]);
close(p[1]);
exit(0);
}
else { // parent
close(p[0]);
write(p[1], &pid, sizeof(pid));
close(p[1]); // The child is able to read the EOF now.
}
}
while ((waitpid(-1, NULL, 0)) > 0)
;
close(p[0]);
close(p[1]);
sprintf(buffer, "I've finished\n");
write(1, &buffer, strlen(buffer));
}
I feel like I am close but I am not using the pipes block poperties correctly.
I need some advice, thanks.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
return 1;
}
int const n = atoi(argv[1]);
for (int i = 0; i < n; i++) {
int p[2];
if (pipe(p) != 0)
return 1;
int pid = fork();
if (pid == 0) {
close(p[1]);
if (read(p[0], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[0]);
fprintf(stdout, "I am child %d and my PID is %d\n", i + 1, pid);
return 0;
}
else if (pid > 0) {
close(p[0]);
if (write(p[1], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[1]);
if (waitpid(pid, NULL, 0) == -1)
return 1;
}
else {
return 1;
}
}
fprintf(stdout, "I've finished\n");
}

C - dup2() not executing

This is my first question so I apologize if I'm omitting anything important. So I've been working on an assignment that handles piping via forking. My code is pretty messy, littered with printf statements so I see what's going on.
I've looked around online and I think I get the idea of how to handle piping, but the problem I'm having is that my code skips dup2() on any file descriptor except inFD and outFD.
Here's the code for my function. Also, from what I understand, my teacher made a macro called CHK which checks for errors. If there is an error (such as dup2 returning -1), it'll terminate with a print to stderr.
My includes, global variables and myhandler() for signal
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <math.h>
#include <signal.h>
// Function calls
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray);
int flagHandler(char **ptrArray, char *inArray, char *outArray);
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray);
// Global Variables
const int STORAGE = 254;
const int MAXITEM = 100;
int inFD; // file descriptor for <
int outFD; // file descriptor for >
int complete = 0; // for sighandler
int readDes = 0;
int writeDes = 1;
int numPipes = 0;
int status;
int forCounter = 0;
int fildes[4];
int pipeIndex = 0;
// MetaChar flags
int lessthanSign = 0; // < flag
int greaterthanSign = 0; // > flag
int firstChildFlag = 0;
int lastChildFlag = 0;
void myhandler(int signum)
{
complete = 1;
}
My main function
int main()
{
char s[STORAGE]; // array of words
char *newargv[MAXITEM];
char inArray[STORAGE]; // for <
char outArray[STORAGE]; // for >
int firstCheck;
int pidBackground; // holds value from fork(), used for background calls
struct stat st; // for stat(), checks if file exists
// dynamic array based on numPipes
// first child doesn't use this array, as it uses newargv[0] and newargv
// only the middle children and last child use this array, hence 10
int *pipeArray = malloc(10 * sizeof(int));
int numLoops = 0;
int i = 0;
signal(SIGTERM, myhandler);
for(;;)
{
// Reset flags here
lessthanSign = 0;
greaterthanSign = 0;
pipeSign = 0;
firstChildFlag = 0;
lastChildFlag = 0;
pipeIndex = 0;
parse(s, newargv, inArray, outArray, pipeArray);
pipeHandler(newargv, inArray, outArray, pipeArray);
wait(NULL);
fflush(NULL);
} // end for
printf("Entering killpg; numLoops = %d\n", numLoops);
killpg(getpid(), SIGTERM);
printf("p2 terminated.\n");
exit(0);
} // end main
Main calls parse which fills in newargv[]. It also fills in inArray[] and outArray[] with the string immediately after a < and > respectively. When detecting a pipe sign, it puts a null on newargv[], as well as putting a value in pipeArray[] for indexing the executable's name in newargv. I omitted the parse() and flagHandler() calls to keep it minimal.
My parseHandler() function
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray)
{
pid_t firstChild;
pid_t firstChildBackground;
pid_t middleChild;
pid_t lastChild;
pid_t lastChildBackground;
int i = 0; // plain integer for for loops
printf("Initializing pipes\n");
//pipe(fildes);
//pipe(fildes + 2);
for (i = 0; i < (2*numPipes); i+=2)
{
printf("pipe initializing; i is %d\n", i);
if (pipe(fildes + i) < 0)
{
perror("pipe initialization failed");
exit(EXIT_FAILURE);
}
}
fflush(stdout);
if ((firstChild = fork()) < 0)
{
perror("First child's fork failed!");
exit(EXIT_FAILURE);
}
printf("firstChild pid = %d\n", getpid());
if (firstChild == 0)
{
if (firstChildFlag == 1)
{
printf("inFD = open...\n");
inFD = open(inArray, O_RDONLY);
printf("Doing dup2 inFD\n");
if (dup2(inFD, STDIN_FILENO) < 0)
{
perror("First child's < dup2 failed");
exit(EXIT_FAILURE);
}
}
printf("doing dup2 fildes[writeDes]\n");
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("First child's dup2 failed");
exit(EXIT_FAILURE);
}
printf("*****doing dup2 fildes[writeDes] was a success!\n");
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (firstChildFlag == 1)
{
lessthanSign = 0;
firstChildFlag = 0;
if (close(inFD) < 0)
{
perror("close inFD failed");
exit(EXIT_FAILURE);
}
}
writeDes += 2;
printf("About to execvp first child\n");
if (execvp(ptrArray[0], ptrArray) < 0)
{
perror("execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((middleChild = fork() < 0))
{
perror("Middle child's fork failed");
exit(EXIT_FAILURE);
}
printf("middleChild pid = %d\n", getpid());
if (middleChild == 0)
{
if (dup2(fildes[readDes], STDIN_FILENO) < 0)
{
perror("Middle child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("Middle child's dup2 on writing failed");
exit(EXIT_FAILURE);
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
readDes += 2;
writeDes += 2;
if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0)
{
perror("Middle child's execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((lastChild = fork() < 0))
{
perror("Last child's fork failed");
exit(EXIT_FAILURE);
}
printf("lastChild pid = %d\n", getpid());
if (lastChild == 0)
{
if (dup2(fildes[readDes], STDOUT_FILENO) < 0)
{
perror("Last child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (lastChildFlag == 1)
{
outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200);
if (dup2(outFD, STDOUT_FILENO) < 0)
{
perror("Last child's > dup2 failed");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (lastChildFlag == 1)
{
greaterthanSign = 0;
lastChildFlag = 0;
if (close(outFD) < 0)
{
perror("close on outFD failed");
exit(EXIT_FAILURE);
}
}
printf("Execvp last child\n");
if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
{
perror("Last child's execvp failed");
exit(EXIT_FAILURE);
}
printf("Last child execvp finished\n");
}
}
}
// Only the parent gets here
printf("Only the parent should be here\n");
printf("My pid is %d\n", getpid());
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
for (;;)
{
pid_t pid;
if (pid = wait(NULL) < 0)
{
perror("wait failed");
exit(EXIT_FAILURE);
}
if (pid == lastChild)
{
printf("Parent is waiting for lastChild\n");
break;
}
}
printf("Parent finished waiting. Returning...\n");
return 0;
}
I did pipe(fildes) before any fork, so that all children and a parent have their copy. Therefore, I must close all file descriptors in each child (after dup2 but before execvp) and the parent. The parent will then wait until it gets the pid of lastChild.
With a lot of printf statements, I have found that no child does the dup2() command (except for dup2(inFD...) and dup2(outFD...) when the flags are appropriate). There is also no error printed.
I printed out my (char) newargv[] and my (int) pipeArray[] and they contain the correct values. It seems to be just the dup2 problem, and I have absolutely no idea what's going wrong with it.
I made a simple text file called test2 containing
ls | sort | cat someString
Where someString is just a file with some text. With all the print statements in the pipeHandler() function my output is:
EDIT: I fixed a couple typos I had. I forgot to lace an extra set of parenthesis on 3 ifs, if ((firstChild = fork()0 < 0)
I now have an infinite loop as the parent is waiting for the lastChild's pid. Here's the output:
Initializing pipes
numpipes = 2
pipe initializing; i is 0
pipe initializing; i is 2
firstChild pid = 20521
firstChild pid = 20522
doing dup2 fildes[writeDes]
middleChild pid = 20521
middleChild pid = 20523
lastChild pid = 20521
Only the parent should be here
My pid is 20521
lastChild pid = 20524
<infinite loop>
I'm still clueless though as to what's going on or what's potentially stopping the child.
#MarkPlotnick you're right! It's not that dup2 isn't executing or anything. Because I did dup2(fildes[1], STDOUT_FILENO), all print statements will be piped.
I fixed the typo mentioned as well. I tried my teacher's test file
< input1 cat|>your.outputc tr a-z A-Z | tr \ q
Which should result with a file called your.outputc. It does, and the contents are input1 with the effects of tr. However, I also have the printf statements at the top of this file.
I assumed the dup2 wasn't working because no printf statement followed, unlike it did in dup2(inFD, STDIN_FILENO), but that's probably because it was STDIN.

Creating a pipe in c between two programs

I have been working on creating a pipe in c between two programs, reader.c and writer.c. I haven't been able to get the input for the pipe program to work. The pipe program is supposed to take in a int, send it to the writer program, which then pipes its output into the reader program for the final output. Below is the code for the three classes. I think I am close but can anyone help me get the initial int input argv[2] into the writer class then into the reader class?
pipe program (communicat.c)
int main(int argc, char *argv[])
{
int fd[2];
pid_t childpid;
int result;
if (argc != 2)
{
printf("usage: communicate count\n");
return -1;
}
pipe(fd);
childpid = fork();
if (childpid == -1)
{
printf("Error in fork; program terminated\n");
return -1;
}
if(childpid == 0)
{
close(1);
dup(fd[1]);
execlp("writer", "writer", fd[1],(char *) NULL);
}
else
{
childpid = fork();
}
if( childpid == 0)
{
close(0);
dup(fd[0]);
close(fd[0]);
close(fd[1]);
execlp("reader", "reader", (char *) NULL);
}
else
{
close(fd[0]);
close(fd[1]);
int status;
wait(&status);
}
return(0);
}
Reader.c
int main()
{
int count; /* number of characters in the line */
int c; /* input read */
count = 0;
while ((c = getchar())!= EOF)
{
putchar(c); count++;
if (count == LINELENGTH)
{
putchar('\n'); count = 0;
}
}
if (count > 0)
putchar('\n');
return 0;
}
Writer.c
int main(int argc, char *argv[])
{
int count; /* number of repetitions */
int i; /* loop control variable */
if (argc != 2)
{
printf("usage: writer count\n");
return -1;
}
else count = atoi(argv[1]);
for (i = 0; i < count; i++)
{
printf("Hello");
printf("hello");
}
return 0;
}
Correct the code to exec writer this way:
if(childpid == 0)
{
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execlp("writer", "writer", argv[1], (char *) NULL);
}

Resources