I'm trying to make 3 kinds of processes(1 proc1, 4 proc2 and 5 proc3) and make them run at the same time. I wrote some code, but there seems to be no overlapping, even with sleep() function, i.e. processes always run in same sequence. I'm wondering if this is a correct way to create multiple processes.
int main() {
setbuf(stdout, NULL);
setbuf(stderr, NULL);
int pid;
pid = fork();
if(pid < 0) {
fprintf(stderr, "Fork error.");
exit(2);
} else if(pid == 0){ //Child
proc1();
exit(0);
} else { //Parent
for(int i=0; i<4; i++) {
int child2ID = fork();
if(child2ID == 0) {
proc2();
exit(0);
}
}
for(int i=0; i<5; i++) {
int child3ID = fork();
if(child3ID == 0) {
proc3();
exit(0);
}
}
}
while(wait(NULL)) {
if(errno == ECHILD)
break;
}
return 0;
}
Related
I've included code that creates a series of child processes to divide the work for a task. There's a random chance for it to terminate (handled by the word_count function from which it calls abort()) and on this event, it should create a new child process to replace it. However, the program is being blocked on the read. I know this code is messy, but I want understand the problem before cleaning it up.
int pipes[nChildProc][2]; //pipe fd[0] is read end, fd[1] is write end
long child_f_size = fsize / nChildProc;
pid_t pids[nChildProc];
//start dividing the work among child processes
for(int i = 0; i < nChildProc; ++i) {
//srand(time(NULL));
//int crash = ((rand() / RAND_MAX + 1.0) < crashRate) ? 1 : 0;
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
//wait for a children to finish
int ret, status, i = 0;
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
if(ret == -1) {
continue;
}
if(ret != 0) {// didn't exit normally
if(pipe(pipes[i]) != 0) {
printf("Failed to create pipe.\n");
exit(1);
}
pid_t pid = fork();
FILE *child_fp;
pids[i] = pid;
if(pid < 0) {
printf("Failed to create child process.\n");
exit(1);
}
else if(pid == 0) { //child process
count_t temp_count = readFromFile(child_fp, fsize, child_f_size, char* name, int i, int nChildProc);
//IPC with the main process
if(write(pipes[i][1], &temp_count, sizeof(temp_count)) == -1)
printf("failed to write to pipe.\n");
close(pipes[i][1]);
close(pipes[i][0]);
exit(0); //deallocate process' memory space
}
}
i = (i + 1) % nChildProc;//loop back to detect more processes that were terminated
}
long bytes;
count_t temp;
temp.linecount = 0;
temp.wordcount = 0;
temp.charcount = 0;
//add up all the values from children to count
printf("time to read.\n");
for(unsigned int j = 0; j < nChildProc; ++j) {
if((bytes = read(pipes[j][0], &temp, sizeof(temp))) < 0) {//blocked here
printf("Failed to read from pipe {%d}.\n", j);
exit(1);
}
if(bytes != 0) {
count.linecount += temp.linecount;
count.wordcount += temp.wordcount;
count.charcount += temp.charcount;
}
close(pipes[j][1]);
close(pipes[j][0]);
}
A couple of issues jump out:
if(ret != 0) {// didn't exit normally you've confused ret (which is the pid) for status (which is the exit code of the child)
You can't call wait on a process twice, since calling wait allows the system to release the resources associated with the process. You have several options on how to rewrite this code:
while(wait(NULL) != -1) { // while there are children to wait on
ret = waitpid(pids[i], &status, WUNTRACED);
One easy way is to use wait then lookup in the array which index it belongs to.
while((pid = wait(&status)) {
if (pid == -1) { // no children to wait on
break;
}
for(int i = 0; i < nChildProc; ++i) {
if (pid == pids[i]) break;
}
if (i >= nChildProc) {
unexpected_pid_do_something_smart();
}
// Leave the rest of the loop the same
Note: I didn't compile or test the above code.
I am required to create a process tree with relationships expressed as in the picture.
The problem is I must create all "nodes" in the order of the alphabet. I have gotten this far but my order is not consistent. I believe I am using waitpid incorrectly?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv)
{
pid_t pidA, pidB, pidC, pidD, pidE, pidF, pidG, pidI;
pidA = fork();
if (pidA < 0)
{
perror("A");
exit(1);
}
else if (pidA == 0)
{
printf("%d: A\n", getpid());
pidB = fork();
if (pidB < 0)
{
perror("B");
exit(1);
}
else if (pidB == 0)
{
printf("%d: B\n", getpid());
waitpid(pidD, NULL, 0);
pidE = fork();
if (pidE < 0)
{
perror("E");
exit(1);
}
else if (pidE == 0)
{
printf("%d: E\n", getpid());
waitpid(pidG, NULL, 0);
pidI = fork();
if (pidI < 0)
{
perror("E");
exit(1);
}
else if (pidI == 0)
{
printf("%d: I\n", getpid());
}
else
{
;
}
}
else
{
pidF = fork();
if (pidF < 0)
{
perror("F");
exit(1);
}
else if (pidF == 0)
{
printf("%d: F\n", getpid());
}
else
{
;
}
}
}
else
{
pidC = fork();
if (pidC < 0)
{
perror("B");
exit(1);
}
else if (pidC == 0)
{
printf("%d: C\n", getpid());
waitpid(pidF, NULL, 0); // !
pidG = fork();
if (pidG < 0)
{
perror("G");
exit(1);
}
else if (pidG == 0)
{
printf("%d: G\n", getpid());
}
else
{
;
}
}
else
{
pidD = fork();
if (pidD < 0)
{
perror("B");
exit(1);
}
else if (pidD == 0)
{
printf("%d: D\n", getpid());
}
else
{
;
}
}
}
}
else
{
;
}
return 0;
}
Output is not consistent so I think this part wouldn't help much.
5644: A
5645: B
5646: C
5647: D
5648: G
5650: F
5649: E
5651: I
The principal problem here is that waitpid only suffices for synchronization when all of the processes are linearly related (i.e., parent process, child process, "grandchild" process, etc.).
However, your processes, as exhibited by the diagram, are not linearly related. You can see this issue arise when you call waitpid(pidD, NULL, 0); from within the B process. Not only is pidD not defined in this context but the D process is not a child of the B process and so waitpid is inappropriate.
#EOF makes a good point that trying to run multiple processes in series defeats the purpose of having multiple processes. However, if you just want to do this exercise as a fun brain teaser, I'd recommend setting up pipes in the original process and then closing the write end when the appropriate process wants to signal that it has exited. The process that is waiting for the first process to end can call select on the read end.
I have a function in C which creates a child process and makes it run execvp.
int Execute(char **arg)
{
pid_t pid;
int status;
if ((pid=fork()) == 0)
{
execvp(arg[0],arg);
perror("Execvp error");
exit(1);
}
else if (pid > 0)
{
waitpid(pid, &status, 0);
}
else
{
perror("Fork error");
exit(2);
}
}
Now I want to alter the function to actually run execvp several times (for example 5), and make the parent process wait for all the children to finish. Tried wrapping it all in for loop, but execvp gets executed just once. I know that basically execvp 'replaces' the current program code, but have no idea whether the iteration does not go on.
Thank you for your help!
First, loop around the process creation collecting the child PIDs
pid_t pid[5];
int i;
for (i = 0; i < 5; i++) {
if ((pid[i]=fork()) == 0) {
execvp(arg[0],arg);
perror("Execvp error");
_exit(1);
}
if (pid[i] < 0) {
perror("Fork error");
}
}
Second, loop around the waitpid call for every valid PID.
for (i = 0; i < 5; i++) {
if (pid[i] > 0) {
int status;
waitpid(pid[i], &status, 0);
if (status > 0) {
// handle a process sent exit status error
}
} else {
// handle a proccess was not started
}
}
I am making my own shell in C. This is my basic code for running a process:
pid_t childpid;
int status;
int ret = 0;
if (strcmp(line[0], "exit") == 0) {
return;
}
childpid = fork();
if (childpid >= 0) {
if (childpid == 0) {
ret = execvp(line[0], &line[0]);
if (ret == -1) {
printf("ERROR\n");
exit(0);
}
exit(ret);
} else {
waitpid(childpid, &status, 0);
ret = WEXITSTATUS(status);
}
} else {
perror("fork");
exit(-1);
}
Where line is a "string array" holding the commands to run.
Now say I want to run a background process - I have to use sigset. A parent doesn't wait for a backgrounded child process, right? How do I handle this without the child becoming a background process?
How can I have 3 processes running in parallel? Is this solution below correct?
In my solution I put some code to see the time elapsed and I think this is tunning in sequential mode. I need to put pid1, pid2 and pid3 running at the same time.
pid = fork();
if(pid == 0) {
//code...
exit(EXIT_SUCCESS);
} else if(pid > 0) {
pid1 = fork();
if(pid1 == 0) {
//pid1 code...
exit(EXIT_SUCCESS);
} else if(pid1 > 0) {
waitpid(pid1, &status, 0);
} else {
printf("Fork error %d.\n", errno);
}
pid2 = fork();
if(pid2 == 0) {
//pid2 code...
exit(EXIT_SUCCESS);
} else if(pid2 > 0) {
waitpid(pid2, &status, 0);
} else {
printf("Fork error %d.\n", errno);
}
pid3 = fork();
if(pid3 == 0) {
//pid3 code...
exit(EXIT_SUCCESS);
} else if(pid3 > 0) {
waitpid(pid3, &status, 0);
} else {
printf("Fork error %d.\n", errno);
}
waitpid(pid, &status, 0);
}
You keep waiting for one child to complete before you launch the next. Try something like:
for (int i = 0; i < 3; ++i)
{
pid = fork();
if (pid < 0)
error
if (pid == 0)
{
child does thing
exit
}
}
for (int i = 0; i < 3; ++i)
{
wait(&status);
}
EDIT
So just change your code to something like this and wait at the end.
if (pid2 == 0)
{
//pid2 code...
exit(EXIT_SUCCESS);
}
else
if (pid2 < 0)
{
printf("Fork error %d.\n", errno);
}
//....same outline for 3, etc.
Check out my wrap program, specifically the code for wrapc. It forks itself twice, execs one child into wrap, reads, writes to wrap, then reads back in the other child.
Your question is somewhat vague -- are you seeing 3 processes running in parallel or not?
the way your code is written you are exiting the child processes straight away.