I am writing a program that creates a pipe, forks, then the parent sends the command line arguments to the child one char at a time. The child is supposed to count them, and then the parent reaps the child and prints out how many arguments there were. Here is what I have so far:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
pid_t pid;
int status;
int comm[2];
char buffer[BUFSIZ];
// set up pipe
if (pipe(comm)) {
printf("pipe error\n");
return -1;
}
// call fork()
pid = fork();
// fork failed
if (pid < 0) {
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
// -- running in child process --
int nChars = 0;
close(comm[1]);
// Receive characters from parent process via pipe
// one at a time, and count them.
while(read(comm[0], buffer, sizeof(buffer)) != '\n')
nChars++;
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
close(comm[0]);
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
char endl='\n';
for (int a = 1; a < argc; a++) {
for (int c = 0; c < strlen(argv[a]); c++) {
write(comm[1], &argv[a][c], 1);
}
}
write(comm[1], &endl, 1);
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
waitpid(pid, &status, 0);
printf("child counted %d chars\n", nChars);
return 0;
}
}
It seems to run endlessly. It must be stuck in one of the loops. What is going wrong?
Code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(int argc, char *argv[])
{
pid_t pid;
int status;
int comm[2];
char buffer[BUFSIZ];
// set up pipe
if (pipe(comm) < 0) {
printf("pipe error\n");
return -1;
}
// call fork()
if((pid = fork()) <0)
{
printf("fork error %d\n", pid);
return -1;
}
else if (pid == 0) {
// -- running in child process --
int nChars = 0;
close(comm[1]);
//printf("%d \n",BUFSIZ);
// Receive characters from parent process via pipe
// one at a time, and count them.
int n;
while( (n =read(comm[0], buffer, BUFSIZ)) >0)
{
buffer[n] = 0;
int oneChar, i = 0,endflag = 0;
while((oneChar = buffer[i])!=0)
{
// printf("%d\n",oneChar);
if(oneChar!=EOF)
nChars++;
else
{
endflag = 1;
break;
}
i++;
}
//printf("%s\n",buffer);
if(endflag)
break;
}
printf("nChar : %d",nChars);
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
//int nChars = 0;
close(comm[0]);
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
int a,c;
char endl='\n';
for ( a = 1; a < argc; a++) {
for ( c = 0; c < strlen(argv[a]); c++) {
write(comm[1], &argv[a][c], 1);
}
}
printf("write end\n");
int end = EOF;
write(comm[1],&end,4);
waitpid(pid, &status, 0);
printf("child counted %d chars\n", WEXITSTATUS(status));
return 0;
}
}
Related
I'm trying to create n child with the same parent, and send the random number from child -> parent.
For now, I have a problem to send random 0/1 from child -> parent.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
pid_t pids[10];
int i;
int n = 10;
/* Start children. */
for (i = 0; i < n; ++i) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
} else if (pids[i] == 0) {
// printf("I am a child with id %d and my parent %d\n",getpid(),getppid());
int random = rand() % 2;
printf("\nChild send random: %d\n",random);
write(pids[1], &random, sizeof(random));
exit(0);
}
else{
int ran;
read(pids[0], &ran, sizeof(ran)); // read from child
printf("\nParent Received: %d\n", ran);
}
}
wait(NULL);
}
The problems are:
first, read and write don't want a pid like first argument but a file descriptor and second, for passing something between two processes you should use a IPC mechanism like pipes:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
int main()
{
pid_t pids[10];
int _pipe[2];
int i;
int n = 10;
int random;
srand(time(NULL));
/* Start children. */
for (i = 0; i < n; ++i) {
//printf("%d\n",i);
pipe(_pipe);
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
} else if (pids[i] == 0) { // Child
random = rand() % 2;
char str[2];
sprintf(str,"%d",random);
//printf("\nChild send random: %d\n",random);
close(_pipe[0]);
write(_pipe[1], str, sizeof(str));
printf("Pipe sended: %s\n",str);
exit(0);
}
else{ // Parent
char string[1];
close(_pipe[1]);
read(_pipe[0],string,sizeof(string)); // read from child
printf("pipe received: %s\n",string);
//printf("\nParent Received: %d\n", ran);
}
}
wait(NULL);
}
I am trying to run three execv("./test",execv_str) in parallel. And I need to print out success message when each of execv() completes successfully.
But now I get result as following:
username#username:~/Desktop/$./test -p
SUCCESS
SUCCESS
SUCCESS
username#username:~/Desktop/$ TESTING
TESTING
TESTING
The expected result will be:
username#username:~/Desktop/$./test -p
TESTING
SUCCESS
TESTING
SUCCESS
TESTING
SUCCESS
username#username:~/Desktop/$
Here is the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int fork_execv()
{
int status;
pid_t pid;
pid = fork();
/* Handling Child Process */
if(pid == 0){
char* execv_str[] = {"./test", NULL};
if (execv("./test",execv_str) < 0){
status = -1;
perror("ERROR\n");
}
}
/* Handling Child Process Failure */
else if(pid < 0){
status = -1;
perror("ERROR\n");
}
return status;
}
int main(int argc, char *argv[]){
if (argc == 1){
sleep(5);
printf("TESTING\n");
}
else{
int i;
for(i = 0; i < 3; ++i){
if (fork_execv() != -1){
printf("SUCCESS\n");
}
}
}
}
How to modify my code to make it work?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int fork_execv()
{
int status;
pid_t pid;
pid = fork();
/* Handeling Chile Process */
if(pid == 0){
char* execv_str[] = {"./test", NULL};
if (execv("./test",execv_str) < 0){
status = -1;
perror("ERROR\n");
}
}
/* Handeling Chile Process Failure */
else if(pid < 0){
status = -1;
perror("ERROR\n");
}
return pid;
}
void handler(int sig){
printf("SUCCESS\n");
}
int main(int argc, char *argv[]){
if (argc == 1){
sleep(5);
printf("TESTING\n");
}
else{
int i;
pid_t process_id;
for(i = 0; i < 3; ++i){
if ((process_id = fork_execv()) != -1){
if(process_id != 0){
signal(SIGCHLD, handler);
waitpid(process_id, NULL, 0);
}
}
}
}
}
Here what I would do. After the fork, I return the pid, check if it isn't 0 (so we are in the father process) and make the father wait for the son. To print "success", I bind the SIGCHLD signal that is triggered when a child process ends. Note that this is a little overkill and put print after the waitpid would have done the job. (But I like to bind signal.)
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int childs[3];
for (int i = 0; i < 3; ++i) {
int p[2];
if (pipe(p) == -1) { perror("pipe"); exit(1); }
pid_t pid = fork();
if (pid) {
close(p[0]);
childs[i] = p[1];
}
else {
close(p[1]);
printf("child %d start\n", i + 1);
char buf[10];
buf[0] = 0;
int r;
if ((r = read(p[0], buf, 9)) == -1) { ... }
printf("child %d read %s (%d), finish\n", i + 1, buf, r);
sleep(2);
exit(0);
}
}
for (int i = 0; i < 3; ++i) {
// if (argc > 1) {
// write(childs[i], "42", 2);
// }
// ============== HERE >>>
close(childs[i]);
}
pid_t pid;
while ((pid = waitpid(-1, NULL, 0)) > 0) {
printf("child %d exited\n", pid);
}
return 0;
}
Output with comment:
child 1 start
child 2 start
child 3 start
child 3 read (0), finish
The next line is displayed after 2 seconds
child 2 read (0), finish
The next line is displayed after 2 seconds
child 1 read (0), finish
I do not write to the channel in the parent. Closing it, I want to give a signal to the child that will be waiting in the read.
It seems that there is a following. Сhild N expected finishes reading from the result 0, it's ok. Children 2 (N-1) and 1 are locked in a read to a child 3 is completed. Then the child 1 is similar will wait.
Why lock occur?
Child processes inherit open file descriptors from their parent. Your main process opens file descriptors in a loop (using pipe, keeping only the write ends). Child 1 inherits no descriptors (except for stdin/stdout/stderr); child 2 inherits childs[0] (the descriptor going to child 1); child 3 inherits childs[0] and childs[1] (the descriptors going to child 1 and 2).
read on a pipe blocks as long as any write descriptor is still open (because it could be used to send more data). So child 1 waits (because child 2 and child 3 still have an open write descriptor) and child 2 waits (because child 3 still has an open write descriptor); only child 3 sleeps and exits. This causes its file descriptors to close, which wakes up child 2. Then child 2 sleeps and exits, closing its file descriptors, which finally wakes up child 1.
If you want to avoid this behavior, you have to close the open file descriptors in each child:
else {
for (int j = 0; j < i; j++) {
close(childs[j]);
}
close(p[1]);
printf("child %d start\n", i + 1);
The write ends of the pipes are getting inherited by the children.
Since filedescriptor are ref-counted, the write end is only considered closed if all references to it are closed.
Below is your code, slightly refactored, with a fix added:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int children_w[3];
for (int i = 0; i < 3; ++i) {
int p[2];
if (0>pipe(p))
{ perror("pipe"); exit(1); }
pid_t pid;
if(0> (pid= fork()))
{ perror("fork"); exit(1); }
if(pid==0) {
/* Fix -- close the leaked write ends */
int j;
for(j=0; j<i; j++)
close(children_w[j]);
/* end fix*/
close(p[1]);
printf("child %d start\n", i + 1);
char buf[10];
buf[0] = 0;
int r;
if ((r = read(p[0], buf, 9)) == -1) { perror("read");/*...*/ }
printf("child %d read %s (%d), finish\n", i + 1, buf, r);
sleep(2);
exit(0);
}
children_w[i] = p[1];
close(p[0]);
}
for (int i = 0; i < 3; ++i) {
// if (argc > 1) {
// write(childs[i], "42", 2);
// }
// ============== HERE >>>
close(children_w[i]);
}
pid_t pid;
while ((pid = waitpid(-1, NULL, 0)) > 0) {
printf("child %d exited\n", pid);
}
return 0;
}
I have an assignment for class and I am confused on this part of the requirements. So we need to make a multi process word counter with n number of processes and n will be an input argument for the program. Each process needs to do their own mini word count of a select portion of the inputted file. So essentially the inputted file will be divided into 1/n parts and split between n processes.
I understand how to fork the processes through a for loop and how to use pipes to send the mini word count from the children processes to the parent process, but I unsure of how to tell a certain process to do a select part of the input file.
Would you use their PID values to check which process they are then assign them their task?
This is my code so far.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MSGLEN 64
#define MESSES 3
int main(){
int fd[2];
pid_t pid;
int result;
//Creating a pipe
result = pipe (fd);
if (result < 0) {
//failure in creating a pipe
perror("pipe error\n");
exit (1);
}
//Creating a child process
for(int i = 0; i < MESSES; i++){
if ((pid = fork()) < 0) {
//failure in creating a child
perror ("fork error\n");
exit(2);
}
if(pid == 0)
break;
}
if (pid == 0) {
// ACTUALLY CHILD PROCESS
char message[MSGLEN];
//Clearing the message
memset (message, 0, sizeof(message));
printf ("Enter a message: ");
//scanf ("%s",message);
fgets (message, 1024, stdin);
close(fd[0]);
//Writing message to the pipe
write(fd[1], message, strlen(message));
close(fd[1]);
close(fd[0]);
exit (0);
}
else {
//Parent Process
char message[MSGLEN];
char *ptr;
long wc;
close(fd[1]);
while (1) {
//Clearing the message buffer
memset (message, 0, sizeof(message));
//Reading message from the pipe
if(read(fd[0], message, sizeof(message)) == 0)
exit(0);
printf("Message entered %s\n",message);
/*
Message entered needs to be in the format of number first space then string for it to work
*/
wc = 0;
wc = strtol(message, &ptr, 10);
printf("The number(unsigned long integer) is %ld\n", wc);
printf("String part is %s", ptr);
}
close(fd[0]);
wait(NULL);
// exit(0);
}
return 0;
}
The key thing to remember when using fork is that the parent and child share the same memory and a copy of everything the parent has is passed to the child. At which point the child has now forked the parents data.
In the code below we're counting how many processes we've created. You could if you wanted use this as an argument in the child ie the nth child gets value n.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define PROCESS_COUNT 50
int main(void) {
pid_t pid;
size_t pid_count = 0;
//pid_t pid_array[PROCESS_COUNT];
for(int i = 0; i < PROCESS_COUNT; i++) {
if ((pid = fork()) < 0) {
perror ("fork error\n");
exit(2);
}
if (pid == 0) {//child
size_t n = 0;
size_t p = getpid();
while(n++ < 2) {
//Next line is illustration purposes only ie I'm taking liberties by
//printing a pid_t value
printf("child %zu has pid_count == %zu\n", p, pid_count);
sleep(1);
}
exit (0);
}
else {
//Count how many process we've created.
pid_count++;
int status;
waitpid( -1, &status, WNOHANG);
}
}
wait(NULL);
return 0;
}
If you want to get really fancy you can use IPC using pipes or shared memory. There are lots of ways to get data from one process to another, sometimes something as simple as temporary files is more than sufficient. For your problem I'd use mmap but it does not need to be that complicated
I am working on an assignment where I have to count the number of chars from the command line arguments. The parent is to pass the child one char at a time and the child is to count the number of chars and return the count to the parent so it can print the number of chars. When I run my program it just sits and does nothing. I think my problem is when I get to the stage of passing the count back to the parent and reaping the child. I think my code is fairly solid up until that point and then that is were I get a little fuzzy. Any help would be greatly appreciated.
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
//
// Child process counts number of characters sent through pipe.
//
// Child process returns number of characters counted to parent process.
//
// Parent process prints number of characters counted by child process.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //for fork and pip
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
pid_t pid;
int comm[2];
int status;
char src;
// set up pipe
if (pipe(comm))
{
printf("Pipe Error!\n");
return -1;
}
// call fork()
pid = fork();
//check if fork failed
if (pid < 0)
{
printf("Fork Error! %d\n", pid);
return -1;
}
if (pid == 0)
{
// -- running in child process --
//close output side of pipe
close(comm[1]);
int nChars = 0;
printf("in child\n");
// Receive characters from parent process via pipe
// one at a time, and count them.
while (read(comm[0], &src, 1))
{
++nChars;
printf("testing child loop = %d\n", nChars);
}
//close input side of pipe
close(comm[0]);
// Return number of characters counted to parent process.
return nChars;
}
else
{
// -- running in parent process --
int nChars = 0;
//close input side of pipe
close(comm[0]);
printf("Assignment 3\n");
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
int i;
for (i = 1; i < argc; ++i) //loop through each argument
{
int j;
for (j = 0; j < strlen(argv[i]); ++j) //loop through each character in argument
write(comm[1], &argv[i][j], 1);
}
//closing the write end of the pipe
close(comm[1]);
// Wait for child process to return. Reap child process.
waitpid(pid, &status, 0);
// Receive number of characters counted via the value
// returned when the child process is reaped
printf("child counted %d chars\n", nChars);
return 0;
}
}
Here is basically how you should have done it - unless you were absolutely forced to go the return code route.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define c2p 0
#define p2c 1
#define READEND 0
#define WRITEEND 1
int main(int argc, char **argv)
{
pid_t pid;
int comm[2][2];
char src;
for (int i = 0; i < 2; ++i)
if (pipe(comm[i]))
errExit("pipe");
if ((pid = fork()) == -1)
errExit("fork");
if (! pid)
{
close(comm[p2c][WRITEEND]);
close(comm[c2p][READEND]);
int nChars = 0;
while (read(comm[p2c][READEND], &src, 1))
++nChars;
write(comm[c2p][WRITEEND], &nChars, sizeof(nChars));
close(comm[c2p][WRITEEND]); //sends eof to parent
printf("child counted %d chars\n", nChars);
return 0;
}
int nChars = 0;
close(comm[p2c][READEND]);
close(comm[c2p][WRITEEND]);
printf("Assignment 3\n");
for (int i = 1; i < argc; ++i) //loop through each argument
{
int len = strlen(argv[i]);
for (int j = 0; j < len; ++j)
write(comm[p2c][WRITEEND], &argv[i][j], 1);
}
close(comm[p2c][WRITEEND]); //sends eof to child
read(comm[c2p][READEND], &nChars, sizeof(nChars)); //should really be in a loop - your task
close(comm[c2p][READEND]);
wait(0);
printf("parent reports %d chars\n", nChars);
return 0;
}