I have encountered some problems while dealing with pipes and child processes.
I need to
- create four child using fork()
- establish two-way communication using pipe() between parent and each child
- read data from a file card.txt containing number of strings
- distribute strings in a round-robin manner to each child A B C D E F G H, child 1 get A E, child 2 get B F and so on
- select one member variable -> send variable to parent using write() and read() as well as close() to close unused pipe end
- print received variable in parent process
An expected output is:
$ ./a.out 1C < card.txt
Child : 1, pid 1593 :
<S2 S3 S9 ><H9 H6 HA H8 ><C6 CK ><D8 DQ D7 D3 >
Child : 2, pid 1594 :
<SA S6 S7 S4 ><H4 HJ H7 ><CQ C9 CT ><DT D2 D9 >
Child : 3, pid 1595 :
<SQ S5 ><H2 ><C7 C5 C8 CA C4 CJ C3 ><DA D5 >
Child : 4, pid 1596 :
<S8 SJ SK ST ><HK HT H5 H3 HQ ><C2 ><D4 D6 >
child 1: H9
parent: child 1 played H9
child 2: CQ
parent: child 2 played CQ
child 3: H2
parent: child 3 played H2
child 4: HK
parent: child 4 played HK
However, actual output is the following:
parent: child 1 played (null)parent: child 2 played (null)parent: child 3 played (null)parent: child 4 played (null)
Why is that? How to solve the problem?
The code created this output:
#include <stdio.h>
#include <string.h>
#define BUFFERSIZE 51
int i=0;
int currpid, s;
char *buf[BUFFERSIZE];
char *array[BUFFERSIZE];
int n;
char *buffer[100];
/** child to parent pipe */
int child_parent[2];
/** parent to child pipe */
int parent_child[2];
/** child2 to parent pipe */
int child2_parent[2];
/** parent to child2 pipe */
int parent_child2[2];
/** child3 to parent pipe */
int child3_parent[2];
/** parent to child3 pipe */
int parent_child3[2];
/** child4 to parent pipe */
int child4_parent[2];
/** parent to child4 pipe */
int parent_child4[2];
void childFunction(){
int j;
for( i = s+1; i < BUFFERSIZE; i += 4 )
{
buf[j] = array[i];
j++;
}
printf("\n<");
int r;
char *e;
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'S');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">");
printf("<");
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'H');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">");
printf("<");
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'C');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">");
printf("<");
for( r = 0; r < j; r++ )
{
int index;
e = strchr(buf[r],'D');
if (e!=NULL){
index = (int)(e-buf[r]);
if (index == 0){
printf("%s ", buf[r]) ;
}
}
}
printf(">\n");
switch (s){
case 0:
close(parent_child[1]);
close(parent_child[0]);
close(child_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child_parent[1], &buffer[0], strlen(buffer[0]));
close(child_parent[1]);
break;
case 1:
close(parent_child2[1]);
close(parent_child2[0]);
close(child2_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child2_parent[1], &buffer[0], strlen(buffer[0]));
close(child2_parent[1]);
break;
case 2:
close(parent_child3[1]);
close(parent_child3[0]);
close(child3_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child3_parent[1], &buffer[0], strlen(buffer[0]));
close(child3_parent[1]);
break;
case 3:
close(parent_child4[1]);
close(parent_child4[0]);
close(child4_parent[0]);
buffer[0] = buf[0];
printf("child %d: %s", s+1, buffer[0]);
write(child4_parent[1], &buffer[0], strlen(buffer[0]));
close(child4_parent[1]);
break;
}
}
void parentFunction(){
switch (s){
case 0:
close(child_parent[1]);
close(parent_child[1]);
close(parent_child[0]);
read(child_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child_parent[0]);
break;
case 1:
close(child2_parent[1]);
close(parent_child2[1]);
close(parent_child2[0]);
read(child2_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child2_parent[0]);
break;
case 2:
close(child3_parent[1]);
close(parent_child3[1]);
close(parent_child3[0]);
read(child3_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child3_parent[0]);
break;
case 3:
close(child4_parent[1]);
close(parent_child4[1]);
close(parent_child4[0]);
read(child4_parent[0],&buffer[0], sizeof(buffer[0]));
printf("parent: child %d played %s", s+1, buffer[0]);
close(child4_parent[0]);
break;
}
}
int main(int argc, char *argv[])
{
int ch;
ssize_t rread;
char *line = NULL;
size_t len = 0;
while (rread = getdelim( &line, &len, '\0', stdin) != -1) {
}
array[i] = strtok(line," ");
while(array[i]!=NULL)
{
array[++i] = strtok(NULL," ");
}
int childlimit = 4;
int childpids[childlimit];
int currpid;
if (pipe(child_parent) == 0 && pipe(parent_child) == 0 && pipe(child2_parent) == 0 && pipe(parent_child2) == 0 && pipe(child3_parent) == 0 && pipe(parent_child3) == 0 && pipe(child4_parent) == 0 && pipe(parent_child4) == 0)
{
for(s=0; s<childlimit; s++){
switch(currpid = fork()){
case 0:
printf("Child : %d, pid %d : ", s+1, getpid() );
childFunction();
break;
case -1:
printf("Error when forking\n");
return 1;
default:
// in the father
childpids[s] = currpid;
parentFunction();
break;
}
}
//wait for all child created to die
waitpid(-1, NULL, 0);
}
}
main()
; delegate the string processing and I/O operations to a function that only runs in the children. You aren't really closing enough file descriptors in the children. You're closing too many file descriptors in the parent if the parent needs to write to its children; if the parent doesn't need to write to the children, why are you bothering with the pipes from parent to children? – Jonathan Leffleri
for loop controls in functions is a disaster. Sometimes, global variables are necessary — when they are, you should use them. Mostly, they're not — and when they aren't, you should not use them. Single-letter global variable names are seldom appropriate. (It is much better to repeat the definition ofi
in each function where it is needed than to do as you've done.) This makes your code very hard to analyze. Your string reading loop only preserves the last 'line' (null-terminated 'line'). I guess that is a way of slurping the entire file in a single operation. – Jonathan Lefflerwaitpid()
waits for any one of the children to die; you need a loop to wait for them all to die. – Jonathan Leffler