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.
Related
I am attempting to send SIGUSR1 to my child process, child_b, after my parent process waits. However, my handler for sigusr1 is not executing and printing my message "pong quitting" at the end of the output.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>
int fd[2][2];
void sig_handler(int signum) {
if (signum == SIGUSR1) {
printf("pong quitting\n");
exit(1);
}
}
void f1() {
int x = 0;
close(fd[0][0]);
close(fd[1][1]);
while (x <= 100) {
printf("ping: %d\n", x);
x++;
if (write(fd[0][1], &x, sizeof(int)) < 0) {
printf("Error writing f1\n");
}
if (read(fd[1][0], &x, sizeof(int)) < 0) {
printf("Error reading f1\n");
}
}
close(fd[0][1]);
close(fd[1][0]);
}
void f2() {
int x = 0;
close(fd[0][1]);
close(fd[1][0]);
while (x <= 100) {
if (read(fd[0][0], &x, sizeof(int)) < 0) {
printf("Error reading f2\n");
}
if (x <= 100)
printf("pong: %d\n", x);
x++;
if (write(fd[1][1], &x, sizeof(int)) < 0) {
printf("Error writing f2\n");
}
}
close(fd[0][0]);
close(fd[1][1]);
}
int main(void) {
for (int i = 0; i < 2; i++) {
if (pipe(fd[i]) < 0) {
printf("Error opening pipe.\n");
return 1;
}
}
pid_t child_a = fork();
if (child_a < 0) {
printf("Error forking child_a.\n");
return 2;
}
if (child_a == 0) {
f1();
} else {
pid_t child_b = fork();
if (child_b < 0) {
printf("Error forking child_b.\n");
return 3;
}
if (child_b == 0) {
signal(SIGUSR1, sig_handler);
f2();
}
else {
waitpid(child_a, NULL, 0);
waitpid(child_b, NULL, 0);
kill(child_b, SIGUSR1);
}
}
return 0;
}
I've tried sleeping both the parent and child, as well as rearranging the order of wait and kill; however, I can not get the signal handler to execute. Any help would be appreciated.
Killing after wait is just fundamentally wrong: the program is dead and gone, you'd either be getting ESCHR or kill an innocent unrelated process.
If you move the wait before kill, then the problems become child_b finishing two quickly (try running it under strace -f and see child_b is already a zombie by the time the kill runs). Adding some sleep(a_lot); or pause(); at the end of child_b would help there.
if (child_b == 0) {
signal(SIGUSR1, sig_handler);
f2();
pause(); //+
}
else {
waitpid(child_a, NULL, 0);
kill(child_b, SIGUSR1); //^
waitpid(child_b, NULL, 0); //v
}
For added async-signal safety, you could also change the handler to be async-signal-safe:
void sig_handler(int signum) {
char m[]="pong quitting\n";
write(1,m,sizeof(m)-1);
_exit(1);
}
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'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;
}
I have the simple producer consumer program in C try to solve it with fork
I get error exactly when producer tries to write on pipe:
I have wrote another program with the same logic but this one does not give me any clue to know why?
Producer failed to write item on pipe: Bad file descriptor
Anyone have idea why I get this error?
Thanks
#define READ 0
#define WRITE 1
int mutex = 1, full = 0, empty = BUFFER_SIZE, x = 0;
void consumer();
void producer();
int wait_(int);
int signal_(int);
int pipefd[2];
int main() {
printf("Starting producer-consumer problem!\n");
//We intend to run the producer in parent process and the consumer in the child process
if (pipe(pipefd) == -1) { /* An error has occurred. */
fprintf(stderr, "%s", "The call to pipe() has failed.\n");
exit(EXIT_FAILURE);
}
for (int j = 0; j < sizeof(pipefd); j++) {
if (pipe(&pipefd[j]) < 0) { //Initialize each pipe appropriately
perror("Error in making pipe...");
}
}
pid_t pid = fork();
if (pid < 0) {
perror("**********Error in creating fork()!**************\n");
exit(STDERR_FILENO);
} else if (pid == 0) {
consumer();//We intend to run the consumer in child
} else {
producer();//We intend to run the producer in parent
}
return 0;
}
int wait_(int s) {
return (--s);
}
int signal_(int s) {
return (++s);
}
void producer() {
printf("Starting Producer\n");
//while (1) {
//sleep(1);
if (close(pipefd[READ]) != 0) {
perror("Error in closing reading pipe");
}
if (write(pipefd[WRITE], &full, 1) < 0) {
perror("Producer failed to write item on pipe");
}
if ((mutex == 1) && (empty != 0)) {
mutex = wait_(mutex);
full = signal_(full);
empty = wait_(empty);
x++;
printf("Producer produces the item %d\n", x);
mutex = signal_(mutex);
}
if (close(pipefd[WRITE]) != 0) {
perror("Error in closing writing pipe");
}
//}
}
void consumer() {
printf("Starting Consumer\n");
//while (1) {
//sleep(1);
int status = 0;
wait(&status); /* wait for all children to return back the result */
if (close(pipefd[WRITE]) != 0) {
perror("Error in closing reading pipe");
}
if (read(pipefd[READ], &full, 1) > 0) {
printf("Consumer\t%d\n", full);
}
if ((mutex == 1) && (full != 0)) {
mutex = wait_(mutex);
full = wait_(full);
empty = signal_(empty);
printf("Consumer consumes item %d\n", x);
x--;
mutex = signal_(mutex);
}
if (close(pipefd[READ]) != 0) {
perror("Error in closing reading pipe");
}
//}
}
The sizeof operator returns the size in bytes. So on a typical system where an int is four bytes, sizeof(pipefd) would result in the value 8. Which is not the correct number of elements for your loop.
Also, pipe(&pipefd[j]) is not correct either. The two pipes in pipefd are already initialized "appropriately". There's no need for any more initialization. Especially since in both this and the previous case you will have undefined behavior.
I have the following piece of code:
int main() {
int n = 1;
if(fork() == 0) {
printf("child");
n = n + 1;
exit(0);
}
n = n + 2;
printf("%d: %d\n", getpid(), n);
wait(0);
return 0;
}
The problem is that I don't understand why the child process is not executing.
The child process is executing only if i set sleep(1) in the parent process
Thanks in advance.
It is getting executed and it should be outputting the text. No newlines should be necessary:
https://ideone.com/a1tznH
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int n = 1;
if(fork() == 0) {
printf("child");
n = n + 1;
exit(0);
}
n = n + 2;
printf("%ld: %d\n", (long)getpid(), n); //this is how you should print pids
wait(0);
return 0;
}
Example output:
child23891: 3
Perhaps you didn't notice the child text was at the beginning of your next prompt:
18188: 3
child[21:17] pskocik#laptop: $
The child is executed but two processes are trying to write on the same FD - STDOUT (File Descriptor).
If you want to see the result, put "\n" in printf of the child.
int main() {
int n = 1;
if(fork() == 0)
{
printf("child\n");
n = n + 1;
exit(0);
}
n = n + 2;
printf("%d: %d\n", getpid(), n);
wait(0);
return 0;
}
Try
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("fail to fork");
}
else if (pid == 0)
{
printf("running child");
exit(0);
}
else
{
print("running parent");
wait(0);
print("child done");
}
return 0;
This is the basic structure of a program I wrote recently which works. Not totally sure why yours didn't work though.