2 way communication between with fork and pipe - c

I'm trying to get 2 way communication between a main file and a helper file.
The main file forks, and the child does some pipe work and then runs an exec.
My problem is that I can send information from the child exec to the parent exec, but not the other way around.
Below Is my entire code from the two files, so you should be able to run it.
Any help in getting the 2 way communication working will be extremely helpful. i'm been at this for almost 8 hours straight now.
When you run it, you'll see it print out "yo 0". This was me testing that it takes an integer from the main file, sends it to the helper, adds yo in front of it and sends it back. The first slab of code is the main file, second is the helper, third is the map file needed to run it. make sure there isn't a blank line underneath the last line, and the fourth is the agent file needed to run it.
the running is [./handler mapfile 20 agentfile.]
the int 20 doesn't do anything yet, but you need it in there to run the file.
If anyone actually goes to the effort to do all this and help me, i am eternally grateful
main file (handler.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/wait.h>
enum ErrorCode {
SHOW_USAGE = 1, BAD_STEPS, OPEN_MAP_ERROR, CORRUPT_MAP,
OPEN_AGENT_ERROR, CORRUPT_AGENTS, AGENT_ERROR,
AGENT_WALLED, AGENT_COLLIDED, TOO_MANY_STEPS, INVALID_AGENT_RESPONSE,
AGENT_CLOSED, AGENT_DIED, SIGINT_REC
};
typedef struct {
int valid;
int row, col;
} Point;
typedef struct {
Point point;
int number;
char name;
char param[20];
char type[20];
} Agent;
typedef struct {
int rows, cols;
char **grid;
} Map;
Map map;
Map agentMap;
int listSize = 0;
void error(enum ErrorCode e) {
switch(e) {
case SHOW_USAGE:
fprintf(stderr, "Usage: handler mapfile maxsteps agentfile\n");
break;
case BAD_STEPS:
fprintf(stderr, "Invalid maxsteps.\n");
break;
case OPEN_MAP_ERROR:
fprintf(stderr, "Unable to open map file.\n");
break;
case CORRUPT_MAP:
fprintf(stderr, "Corrupt map.\n");
break;
case OPEN_AGENT_ERROR:
fprintf(stderr, "Unable to open agent file.\n");
break;
case CORRUPT_AGENTS:
fprintf(stderr, "Corrupt agents.\n");
break;
case AGENT_ERROR:
fprintf(stderr, "Error running agent.\n");
break;
case AGENT_WALLED:
fprintf(stderr, "Agent walled.\n"); // needs fixing, check spec sheet
break;
case AGENT_COLLIDED:
fprintf(stderr, "Agent collided.\n"); // same as AGENT_WALLED
break;
case TOO_MANY_STEPS:
fprintf(stderr, "Too many steps.\n");
break;
case INVALID_AGENT_RESPONSE:
fprintf(stderr, "Agent sent invalid response.\n"); // fixiing
break;
case AGENT_CLOSED:
fprintf(stderr, "Agent exited with status.\n"); // fixiing
break;
case AGENT_DIED:
fprintf(stderr, "Agent exited due to signal.\n"); // fixing
break;
case SIGINT_REC:
fprintf(stderr, "Exiting due to INT signal.\n");
break;
}
exit(e);
}
void print_map(Map map)
{
int r;
for (r = 0; r < map.rows; ++r) {
printf("%s", map.grid[r]);
}
puts("");
}
void print_agents(Agent *agents, int size)
{
int i;
for (i = 0; i < size; i++) {
Agent temp = agents[i];
printf("%d %d %c %d %s %s %i\n", temp.point.row, temp.point.col, temp.name, temp.number, temp.type, temp.param, i);
}
puts("");
}
void readMap(char *file)
{
int r;
FILE *fd = fopen(file, "r");
char buffer[20];
char d;
if (!fd) {
error(OPEN_MAP_ERROR);
}
if (fgets(buffer, 20, fd) == NULL) {
error(CORRUPT_MAP);
}
if (sscanf(buffer, "%d %d%1[^\n]\n", &map.rows, &map.cols, &d) != 2 ||
map.rows < 1 || map.rows > 999 || map.cols < 1 || map.cols > 999) {
error(CORRUPT_MAP);
}
map.grid = malloc(map.rows * sizeof(char *));
for (r = 0; r < map.rows; ++r) {
map.grid[r] = calloc(map.cols + 2, sizeof(char));
if (fgets(map.grid[r], map.cols + 2, fd) == NULL ||
map.grid[r][map.cols] != '\n') {
error(CORRUPT_MAP);
}
}
fclose(fd);
}
void checkAgent(char *file)
{
FILE *fd = fopen(file, "r");
if (!fd) {
error(AGENT_ERROR);
}
fclose(fd);
}
int growList (Agent **agentList, int curSize, int increaseNum)
{
const int newSize = curSize + increaseNum;
Agent *temp = (Agent*) realloc(*agentList, (newSize * sizeof(Agent)));
if (temp == NULL) {
exit(20);
}
else {
*agentList = temp;
return newSize;
}
}
Agent* readAgentFile(char *file, Agent *agentList)
{
int readCount = 0;
FILE *fp = fopen(file, "r");
char buffer[80];
listSize = 0;
if (!fp) {
error(OPEN_AGENT_ERROR);
}
if (fgets(buffer, 80, fp) == NULL) {
error(CORRUPT_AGENTS);
}
rewind(fp);
while (fgets(buffer, 80, fp) != NULL) {
if (buffer[0] != '#') {
Agent agent;
sscanf( buffer, "%d %d %c %s %s" ,&agent.point.row, &agent.point.col, &agent.name, agent.type, agent.param);
checkAgent(agent.type);
agent.number = readCount+1;
listSize = growList(&agentList, listSize, 1);
agentList[readCount] = agent;
readCount++;
}
}
if (readCount == 0) {
error(CORRUPT_AGENTS);
}
fclose(fp);
return agentList;
}
void createAgentMap()
{
int i,j;
agentMap = map;
for (i=0; i < map.rows; i++) {
for (j=0; j < map.cols; j++) {
char c = map.grid[i][j];
if (c == '.') {
agentMap.grid[i][j] = ' ';
}
}
}
}
int main(int argc, char **argv)
{
int steps;
int pid;
int returnStatus;
int i;
int out_pipe[2];
int in_pipe[2];
char ch[20];
Agent firstAgent;
Agent *agentList =(Agent *) calloc(1, sizeof(Agent));
if (argc != 4) {
error(SHOW_USAGE);
}
sscanf(argv[2], "%d", &steps);
if ((steps < 1)) {
error(BAD_STEPS);
}
readMap(argv[1]);
agentList = readAgentFile(argv[3], agentList);
firstAgent = agentList[0];
createAgentMap();
for (i=0; i < listSize; i++) {
if (pipe(out_pipe) < 0) {
perror("Pipe Error");
}
if (pipe(in_pipe) < 0) {
perror("Child pipe error");
}
Agent temp;
temp = agentList[i];
switch ( pid = fork() )
{
case -1:
perror("Can't fork.\n");
exit(20);
case 0:
/* Child */
/*close(1);
dup(in_pipe[1]);
close(0);
dup(out_pipe[0]);
close(in_pipe[0]);
close(out_pipe[1]);*/
dup2(out_pipe[0], 0);
dup2(in_pipe[1], 1);
execlp(temp.type, temp.type, temp.param, (char *)0);
perror("No exec");
default:
//close(1);
//dup(handlerChild[1]);
//fprintf(stdout, "%d", listSize);
write(out_pipe[1], "%d", listSize);
close(in_pipe[1]);
close(0);
dup(in_pipe[0]);
if (fgets(ch, 20, stdin) == NULL) {
break;
}
printf("%s\n", ch);
}
}
while (steps > 0) {
steps -= 1;
}
return 0;
}
helper file (simple.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct {
int valid;
int row, col;
} Point;
typedef struct {
int numAgents;
char agentNames[80];
int agentNumber;
} Info;
typedef struct {
int rows, cols;
char **grid;
} Map;
Map agent_map;
int main(int argc, char **argv)
{
int steps = 10;
int simple_pipe[2];
int dir;
char inputDir;
char input_stream[20];
int in = dup(0);
Info info;
if (argc == 2) {
sscanf(argv[1], "%c1", &inputDir);
switch (inputDir) {
case 'N': dir = 0; break;
case 'E': dir = 1; break;
case 'S': dir = 2; break;
case 'W': dir = 3; break;
default : fprintf(stdout, "Invalid params.\n"); exit(2);
}
}
else {
fprintf(stdout, "Incorrect number of params.\n");
exit(1);
}
close(0);
dup(simple_pipe[0]);
fgets(input_stream, 20, stdin);
sscanf(input_stream, "%d", &info.numAgents);
//printf("%d", info.numAgents);
//printf("this is the input: %s\n", input_stream); // This is successfully printing to stdout in the pipe
fprintf(stderr, "yo %d \n", info.numAgents);
while (steps > 0) {
steps -= 1;
}
exit(0);
}
map file
6 6
##..##
#....#
#.##.#
#....#
##....
######
agent file
1 1 A ./simple E
2 2 B ./simple N
5 2 C ./simple S

A pipe is a unidrectional connection across processes. Before you fork, you open the pipe and it will reserve two file descriptors, where fd[0] can be read from and fd[1] can be written to.
So when you want to have a two way commumincation you need to create two pipes, and then use one for reading in the parent writing in the child and the second pipe the other way around.
A more detailed explanation along with some sample code can be foun dhere: http://linux.die.net/man/2/pipe

Related

warning when compiling with make

I wrote a program that copies the standard entry into the stdout as well as into a file. The program works but I have a problem, I receive a warning when compiling with make:
warning: implicit declaration of function ‘isprint’ [-Wimplicit-function-declaration]
if (isprint(optopt))
^~~
code:
Although it's not a big deal, I'd like it to stop displaying this warning. What would be the problem? I would also like a review of the code, what could I improve?
The program behaves like the tee -a file command.
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
static int append_mode = 0;
int parse_args(int argc, char *argv[])
{
char c;
while ((c = getopt(argc, argv, "a")) != -1) {
switch (c) {
case 'a':
append_mode = 1;
break;
case '?':
if (isprint(optopt))
fprintf(stderr, "Unkonw option `-%c'.\n", optopt);
else
fprintf(stderr,
"Unknown option character `\\x%x'.\n", optopt);
return 1;
default:
abort();
break;
}
}
return 0;
}
int main(int argc, char *argv[])
{
char buf[100];
size_t len;
char *file_mode;
int i;
FILE *files[20];
int num_files;
if (parse_args(argc, argv)) {
return 1;
}
file_mode = (append_mode ? "a" : "w");
num_files = argc - optind;
if (num_files > 0) {
if (files == NULL) {
fprintf(stderr, "Unable to allocate file buffer space\n");
return 1;
}
/* go through file arguments and either open for writing
or append based on the -a flag */
for (i = optind; i < argc; i++) {
FILE *pFile = fopen(argv[i], file_mode);
if (pFile == NULL)
{
fprintf(stderr, "Unable to open file %s for mode %s",
argv[i], file_mode);
goto main_cleanup;
}
files[i - optind] = pFile; /* mind the offset */
}
}
FILE *not_stdin = fopen("tee.c", "r");
while ((len = fread(&buf[0], 1, sizeof(buf), not_stdin)) > 0) {
fwrite(&buf[0], 1, len, stdout);
for (i = 0; i < num_files; i++) {
fwrite(&buf[0], 1, len, files[i]);
}
}
main_cleanup:
if (num_files > 0) {
for (i = 0; i < num_files; i++) {
fclose(files[i]);
}
}
return 0;
}
Mostly this warning appears when you are trying to use a function without including its required header.
To use isprint() add #include <ctype.h> to your included headers.

Parsing words from text file using multithreading using C

Currently I am attempting to parse words from all text files in a directory (in this case it is safe to assume there will only be text files within the directory). It seems as though I am able to open the file within the threads function, however I am unable to grab the text within. No error messages are being presented but the printf within splitInput is not printing to the terminal.
Forgive my semantic work within the code, I am a fresh novice with C! Along with this there may be unused code within main as this will be part of a larger project. I appreciate the assistance in advance!
#include <stdlib.h>
#include <dirent.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "queue.h"
void* splitInput(void *filename) {
printf("Thread %s Created\n", (char*)filename);
FILE *file;
int i = 0;
char *cp;
char *bp;
char line[255];
char *array[5000];
file = fopen((char*)filename, "r");
if(file == NULL) {
perror("Error opening file");
}
printf("Opened File %s\n", (char*)filename);
while(fgets(line, sizeof(line), file) != NULL) {
bp = line;
while(1) {
cp = strtok(bp, ",.!? \n");
bp = NULL;
if(cp == NULL) {
break;
}
array[i++] = cp;
printf("Check print - word %i:%s:\n", i-1, cp);
}
}
fclose(file);
return 0;
}
int main(int argc, char *argv[]) {
DIR* d;
struct dirent* e;
// grab our queueSize and threadCount
int queueSize = atoi(argv[2]);
int threadCount = atoi(argv[3]);
// var for creating a thread each file
int i = 0;
// open the dir
d = opendir(argv[1]);
printf("Queue Size: %d\n", queueSize);
printf("Thread Count: %d\n", threadCount);
// set our thread count now that we know how many files are in dir
pthread_t threads[threadCount];
// read through our directory
while((e = readdir(d)) != NULL) {
// make sure we aren't reading . and ..
if(strcmp(e->d_name, ".") == 0) {
continue;
}
if(strcmp(e->d_name, "..") == 0) {
continue;
}
printf("entered file %s\n", e->d_name);
char *filename = strdup(e->d_name);
if(i < threadCount) {
// create our threads
pthread_create(&threads[i], NULL, splitInput, filename);
}
// increment i
i++;
}
// join our existing threads
for(int j = 0; j < i; j++) {
pthread_join(threads[j], NULL);
}
return 0;
}
Current Output
device#user:~/os/testdir$ ./output ~/os/testdir/test 10 10 output
Queue Size: 10
Thread Count: 10
entered file test
Thread test Created
Opened File test
Found the answer, I was attempting to open a file outside my working directory which cannot be done without the full path. Changing the working directory to the parameter given solved the issue. This can be done in this case with chdir(argv[1])
Revised code below.
#include <stdlib.h>
#include <dirent.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include "queue.h"
void* splitInput(void *filename) {
printf("Thread %s Created\n", (char*)filename);
FILE *file;
int i = 0;
char *cp;
char *bp;
char line[255];
char *array[5000];
file = fopen((char*)filename, "r");
if(file == NULL) {
perror("Error opening file");
}
printf("Opened File %s\n", (char*)filename);
while(fgets(line, sizeof(line), file) != NULL) {
bp = line;
while(1) {
cp = strtok(bp, ",.!? \n");
bp = NULL;
if(cp == NULL) {
break;
}
array[i++] = cp;
printf("Check print - word %i:%s:\n", i-1, cp);
}
}
fclose(file);
return 0;
}
int main(int argc, char *argv[]) {
DIR* d;
struct dirent* e;
// grab our queueSize and threadCount
int queueSize = atoi(argv[2]);
int threadCount = atoi(argv[3]);
// var for creating a thread each file
int i = 0;
// open the dir
chdir(argv[1]);
d = opendir(argv[1]);
printf("Queue Size: %d\n", queueSize);
printf("Thread Count: %d\n", threadCount);
// set our thread count now that we know how many files are in dir
pthread_t threads[threadCount];
// read through our directory
while((e = readdir(d)) != NULL) {
// make sure we aren't reading . and ..
if(strcmp(e->d_name, ".") == 0) {
continue;
}
if(strcmp(e->d_name, "..") == 0) {
continue;
}
printf("entered file %s\n", e->d_name);
char *filename = strdup(e->d_name);
if(i < threadCount) {
// create our threads
pthread_create(&threads[i], NULL, splitInput, filename);
}
// increment i
i++;
}
// join our existing threads
for(int j = 0; j < i; j++) {
pthread_join(threads[j], NULL);
}
return 0;
}

Unable to find the source of infinite loop

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/utsname.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<pwd.h>
#include<sys/wait.h>
#include<signal.h>
#define MAX_NO_OF_CMD_ELEMENTS (10)
struct utsname u; /* to get hostname*/
struct passwd *pw; /*to get username*/
int pid;
char* username, *hostname;
char cwd[100];
char *basedir;
int bg;
void init_prompt()
{
getcwd(cwd,100);
basedir = cwd;
uname(&u);
pw = getpwuid(getuid());
username = pw->pw_name;
hostname = u.nodename;
}
void prompt_me()
{
sleep(1);
getcwd(cwd,100);
bg =0;
printf("%s#%s:%s$ ",username,hostname,cwd);
}
void pinfo(char **argv)
{
char path[1024];
char c;
char buf[1024];
char filename[1000];
printf("pid --- %s\n",argv[1]);
sprintf(filename,"/proc/%s/status",argv[1]);
FILE *f = fopen(filename, "r");
FILE *fp;
char state;
fgets(buf,1024,f);
fgets(buf,1024,f);
sscanf(buf, "State: %c\n", &state);
printf("process state = %c\n", state);
fclose(f);
char target_path[1024];
sprintf(filename, "/proc/%d/exe",pid);
int len = readlink (filename, target_path, sizeof (target_path));
char buffer[1024];
if(len ==-1)
{
perror("readlink");
}
else
{
target_path[len] = '\0';
printf("executable path: %s\n", target_path);
}
}
void pwd_me()
{
getcwd(cwd,100);
printf("%s",cwd);
}
void cd_me(char **argv)
{
chdir(argv[1]);
if(getcwd(cwd,100)!=0)
{
perror(" ");
}
if(strcmp("~\0",argv[1])==0||strcmp("\0",argv[1])==0)
chdir(basedir);
}
void echo_me(char **argv,int num)
{
int i;
for(i=0;i<num;i++)
{
printf("%s", argv[i]);
if(i!=0 || i!=num-1)
{
printf(" ");
}
}
}
void execute(char **argv,int num)
{
int i;
pid_t pid;
int status;
if ((pid = fork()) < 0)
{ /* fork a child process*/
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0)
{ /* for the child process: */
if(strcmp(argv[0],"cd")==0)
cd_me(argv);
else if(strcmp(argv[0],"pwd")==0)
pwd_me();
else if(strcmp(argv[0],"echo")==0)
echo_me(argv,num);
else if(strcmp(argv[0],"pinfo")==0)
pinfo(argv);
else if(strcmp(argv[0],"exit")==0)
return;
int c;
if (c==execvp(argv[0], argv) < 0)
{ /* execute the command */
printf("%d\n", c);
printf("*** ERROR: exec failed\n");
perror(" ");
exit(1);
}
}
else if(bg!=1){
while (wait(&status) != pid);
}
}
void input()
{
int i,j,n,len,c;
char *buffer = 0;
size_t bufsize = 0;
ssize_t characters;
char *cmd[MAX_NO_OF_CMD_ELEMENTS+1];
characters = getline(&buffer, &bufsize, stdin);
len = strlen(buffer);
buffer[len-1]='\0';
if (characters > 0)
{
char *end_str1;
char *token1 = strtok_r(buffer, ";", &end_str1);
int count = 0, wordcnt;
while (token1 != NULL)
{
char *token2;
memset(cmd,0,sizeof(cmd));
char * cmd[MAX_NO_OF_CMD_ELEMENTS + 1]; /* 1+ for the NULL-terminator */
size_t wordcnt = 0;
char *end_str2;
count++;
token2 = strtok_r(token1, " ", &end_str2);
while ((NULL != token2)
&& (MAX_NO_OF_CMD_ELEMENTS > wordcnt)) /* Prevent writing
out of `cmd`'s bounds. */
{
cmd[wordcnt] = token2;
wordcnt++;
token2 = strtok_r(NULL, " ", &end_str2);
}
if(token2==NULL)
{
cmd[wordcnt] = NULL;
execute(cmd, wordcnt);
}
}
}
free(buffer);
}
int main()
{
init_prompt();
while(1)
{
prompt_me();
input();
}
}
I am unable to find the source of the infinite loop that occurs while running this program. Please help?
I think it is most likely to be in the input function, but I'm not sure so to be safe I included the whole program.
Add the following line to the end of the while (token1 != NULL) loop in the input function:
token1 = strtok_r(NULL, ";", &end_str1);
The problem is that you are not updating token1, therefore, token1 will never be NULL, and thus while (token != NULL) will loop forever.
See The linux man page on strtok_r(3)

Issues with forking process and pipes in C program

C beginner here. My C program is supposed to read a file input.txt line by line and then write a line to one of the mapper_pipes. There are four lines of text and each line gets sent to a different mapper pipe. 4 processes are forked, one for each of the lines of text. The program is properly reading the lines of text from the file, I know because I console log them in the send_line_to_mapper function. The code inside the mapper forks which seem to be working since printf("hello from mapper/n"); prints but it does not print the messages sent through the pipe here printf("forked mapper read line: %s\n", ibuf);. Appreciate any help.
Update 2
*Edit: I moved close to immediatly after fork and now its working.
Closed write end of the pipe after writing to pipe and after forking process that reads from pipe, still not reading EOF.
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#define BUFFER_SIZE 1024
#define ALPHA_OFFSET 97
#define LETTERS 26
const int NUM_OF_MAPPERS = 4;
const int NUM_OF_REDUCERS = 26;
const int PIPE_READ_END = 0;
const int PIPE_WRITE_END = 1;
const int PIPE_BUFFER_SIZE = 1000;
int mapper_pipes[4][2];
int reducer_pipes[26][2];
void pipe_wrapper(int pipefd[]) {
int ret = pipe(pipefd);
if (ret == -1) {
perror("Error. Failed when trying to create pipes.");
exit(EXIT_FAILURE);
}
}
void create_mapper_pipes(void) {
int i;
for (i = 0; i < NUM_OF_MAPPERS; i++) {
pipe_wrapper(mapper_pipes[i]);
}
}
void create_reducer_pipes(void) {
int i;
for (i=0; i < NUM_OF_REDUCERS; i++) {
pipe_wrapper(reducer_pipes[i]);
}
}
// Prints an error msg and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val, const char* syscall_name) {
if (syscall_val < 0) {
perror(syscall_name);
exit(errno);
} else {
//No syscall error we can return
return syscall_val;
}
}
void fork_mappers(void) {
/* Constants useful to all children */
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i=0; i<NUM_OF_MAPPERS; i++) {
pid_t mapper_pid = print_if_err(fork(), "fork");
if (mapper_pid == 0) {
close(mapper_pipes[i][PIPE_WRITE_END]);
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
while(rlen > 0) {
printf("read line from forked_mappers, p%d: %s\n", i, ibuf);
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
}
_exit(0);
}
}
}
void fork_reducers(void) {
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
pid_t reducer_pid = print_if_err(fork(), "fork");
if (reducer_pid == 0) {
}
}
}
void send_lines_to_mappers(void) {
int wlen = 0;
char obuf[PIPE_BUFFER_SIZE];
int ob_size;
int count = 0;
char buff[BUFFER_SIZE]; // a buffer for each line of the file
FILE *input_file = fopen("input.txt", "r");
// read the input file line by line
while(fgets(buff, BUFFER_SIZE, input_file) > 0) {
printf("read line from send_lin_to_mappers: %s\n", buff);
ob_size = sizeof buff;
switch(count) {
case 0 :
write(mapper_pipes[0][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[0][PIPE_WRITE_END]);
break;
case 1 :
write(mapper_pipes[1][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[1][PIPE_WRITE_END]);
break;
case 2 :
write(mapper_pipes[2][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[2][PIPE_WRITE_END]);
break;
case 3 :
write(mapper_pipes[3][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[3][PIPE_WRITE_END]);
break;
default :
printf("you did something wrong in send_lines_to_mappers loop");
}
count++;
}
fclose(input_file);
}
int main(void) {
// Setup the mapper pipes
create_mapper_pipes();
create_reducer_pipes();
fork_mappers();
//fork_reducers();
send_lines_to_mappers();
return 0;
}
Updated Code After Help From Comments
Now everything seems to be working but forked processes in fork_mappers never leave while loop and exit.
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#define BUFFER_SIZE 1024
#define ALPHA_OFFSET 97
#define LETTERS 26
const int NUM_OF_MAPPERS = 4;
const int NUM_OF_REDUCERS = 26;
const int PIPE_READ_END = 0;
const int PIPE_WRITE_END = 1;
const int PIPE_BUFFER_SIZE = 1000;
int mapper_pipes[4][2];
int reducer_pipes[26][2];
void pipe_wrapper(int pipefd[]) {
int ret = pipe(pipefd);
if (ret == -1) {
perror("Error. Failed when trying to create pipes.");
exit(EXIT_FAILURE);
}
}
void create_mapper_pipes(void) {
int i;
for (i = 0; i < NUM_OF_MAPPERS; i++) {
pipe_wrapper(mapper_pipes[i]);
}
}
void create_reducer_pipes(void) {
int i;
for (i=0; i < NUM_OF_REDUCERS; i++) {
pipe_wrapper(reducer_pipes[i]);
}
}
// Prints an error msg and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val, const char* syscall_name) {
if (syscall_val < 0) {
perror(syscall_name);
exit(errno);
} else {
//No syscall error we can return
return syscall_val;
}
}
void fork_mappers(void) {
/* Constants useful to all children */
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i=0; i<NUM_OF_MAPPERS; i++) {
pid_t mapper_pid = print_if_err(fork(), "fork");
if (mapper_pid == 0) {
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
while(rlen > 0) {
printf("read line from forked_mappers, p%d: %s\n", i, ibuf);
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
}
_exit(0);
}
}
}
void fork_reducers(void) {
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
pid_t reducer_pid = print_if_err(fork(), "fork");
if (reducer_pid == 0) {
}
}
}
void send_lines_to_mappers(void) {
int wlen = 0;
char obuf[PIPE_BUFFER_SIZE];
int ob_size;
int count = 0;
char buff[BUFFER_SIZE]; // a buffer for each line of the file
FILE *input_file = fopen("input.txt", "r");
// read the input file line by line
while(fgets(buff, BUFFER_SIZE, input_file) > 0) {
printf("read line from send_lin_to_mappers: %s\n", buff);
ob_size = sizeof buff;
switch(count) {
case 0 :
write(mapper_pipes[0][PIPE_WRITE_END], buff, ob_size);
break;
case 1 :
write(mapper_pipes[1][PIPE_WRITE_END], buff, ob_size);
break;
case 2 :
write(mapper_pipes[2][PIPE_WRITE_END], buff, ob_size);
break;
case 3 :
write(mapper_pipes[3][PIPE_WRITE_END], buff, ob_size);
break;
default :
printf("you did something wrong in send_lines_to_mappers loop");
}
count++;
}
fclose(input_file);
}
int main(void) {
// Setup the mapper pipes
create_mapper_pipes();
create_reducer_pipes();
fork_mappers();
//fork_reducers();
send_lines_to_mappers();
return 0;
}
C Code
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#define BUFFER_SIZE 1024
#define ALPHA_OFFSET 97
#define LETTERS 26
const int NUM_OF_MAPPERS = 4;
const int NUM_OF_REDUCERS = 26;
const int PIPE_READ_END = 0;
const int PIPE_WRITE_END = 1;
const int PIPE_BUFFER_SIZE = 32;
int mapper_pipes[4][2];
int reducer_pipes[26][2];
void pipe_wrapper(int pipefd[]) {
int ret = pipe(pipefd);
if (ret == -1) {
perror("Error. Failed when trying to create pipes.");
exit(EXIT_FAILURE);
}
}
void create_mapper_pipes(void) {
int i;
for (i = 0; i < NUM_OF_MAPPERS; i++) {
pipe_wrapper(mapper_pipes[i]);
}
}
void create_reducer_pipes(void) {
int i;
for (i=0; i < NUM_OF_REDUCERS; i++) {
pipe_wrapper(reducer_pipes[i]);
}
}
// Prints an error msg and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val, const char* syscall_name) {
if (syscall_val < 0) {
perror(syscall_name);
exit(errno);
} else {
//No syscall error we can return
return syscall_val;
}
}
void fork_mappers(void) {
/* Constants useful to all children */
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i=0; i<NUM_OF_MAPPERS; i++) {
pid_t mapper_pid = print_if_err(fork(), "fork");
printf("%d\n", mapper_pid);
if (mapper_pid == 0) {
printf("hello from mapper/n");
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
while(rlen > 0) {
printf("forked mapper read line: %s\n", ibuf);
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
}
_exit(0);
}
}
}
void fork_reducers(void) {
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
pid_t reducer_pid = print_if_err(fork(), "fork");
if (reducer_pid == 0) {
}
}
}
void send_lines_to_mappers(void) {
int wlen = 0;
char obuf[PIPE_BUFFER_SIZE];
int obptr = 0;
int count = 0;
char buff[BUFFER_SIZE]; // a buffer for each line of the file
FILE *input_file = fopen("input.txt", "r");
// read the input file line by line
while(fgets(buff, BUFFER_SIZE, input_file) > 0) {
printf("read line: %s\n", buff);
switch(count) {
case 0 :
write(mapper_pipes[0][PIPE_WRITE_END], obuf, obptr);
break;
case 1 :
write(mapper_pipes[1][PIPE_WRITE_END], obuf, obptr);
break;
case 2 :
write(mapper_pipes[2][PIPE_WRITE_END], obuf, obptr);
break;
case 3 :
write(mapper_pipes[3][PIPE_WRITE_END], obuf, obptr);
break;
default :
printf("you did something wrong in send_lines_to_mappers loop");
}
count++;
}
fclose(input_file);
}
int main(void) {
// Setup the mapper pipes
create_mapper_pipes();
create_reducer_pipes();
fork_mappers();
//fork_reducers();
send_lines_to_mappers();
return 0;
}
Output
9592
9593
9594
9595
read line: I like coding in C.
read line: I like manually allocating memory, and opening the registers window in Visual Studio to see the values of the eax register and blitting graphics to the screen and all the stuff that Dr. Dobbs wrote about in the 90s.
read line: My programming friends seem to believe that understanding this level of programming is good in a hand-wavy, theoretical sense, but when you consider all the web development, Java frameworks, and existing libraries most programmers today rely on, it's hard to really pin down a solid answer to the question "Why learn C?"
read line: This is my attempt to answer that question, and I believe it comes down to the basic programming concept of abstraction.
0
0
0
0

Read does not receive EOF even though I close all my pipes C

Trying to give a Minimal Viable Example of the problem. Basically the method send_chars_to_reducers sends a character to the proper reducer_pipe. The fork_reducers function remains in its while loop until it receives EOF but it never does even though I close all reducer pipes in send_chars_to_reducers. I know it doesnt exit the while loop because it never prints exiting reducers.
C Code
void send_chars_to_reducers(char * line) {
printf("SEND_CHARS_TO_REDUCERS read: %s\n\n", line);
int i;
int ob_size = 1;
int wlen = 0;
for (i = 0; i < strlen(line); i++) {
if (line[i] >= ALPHA_OFFSET && line[i] < ALPHA_OFFSET + LETTERS) {
int pipe_num = line[i] - ALPHA_OFFSET;
printf("SENDING %c TO REDUCER PIPE %d\n", line[i], pipe_num);
wlen = print_if_err(write(reducer_pipes[pipe_num][PIPE_WRITE_END], &line[i], ob_size), "write");
printf("WROTE %s to REDUCER %d\n", line[i], i);
}
}
close_reducer_pipes();
}
void close_reducer_pipes(void) {
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
close(reducer_pipes[i][PIPE_WRITE_END]);
close(reducer_pipes[i][PIPE_READ_END]);
}
}
void fork_mappers(void) {
/* Constants useful to all children */
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i=0; i<NUM_OF_MAPPERS; i++) {
pid_t mapper_pid = print_if_err(fork(), "fork");
if (mapper_pid == 0) {
int j;
for (j=0; j < NUM_OF_MAPPERS; j++) {
close(mapper_pipes[i][PIPE_WRITE_END]);
if (j != i) {
close(mapper_pipes[j][PIPE_READ_END]);
}
}
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
send_chars_to_reducers(ibuf);
close_reducer_pipes();
//printf("forked mapper%d read: %s\n\n", i, ibuf);
close(mapper_pipes[i][PIPE_READ_END]);
_exit(0);
}
}
}
void fork_reducers(void) {
printf("HELLLOOOO FROM REDUCER\n");
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
pid_t reducer_pid = print_if_err(fork(), "fork");
if (reducer_pid == 0) {
while (1) {
rlen = print_if_err(read(reducer_pipes[i][PIPE_READ_END], ibuf, 1), "read");
if (rlen > 0) {
printf("REDUCER #%d, read %s\n", i, ibuf);
} else {
break;
}
}
printf("exiting reducer\n");
_exit(0);
}
}
}
Entire C Code
#include <sys/wait.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#define BUFFER_SIZE 1024
#define ALPHA_OFFSET 97
#define LETTERS 26
const int NUM_OF_MAPPERS = 4;
const int NUM_OF_REDUCERS = 26;
const int PIPE_READ_END = 0;
const int PIPE_WRITE_END = 1;
const int PIPE_BUFFER_SIZE = 1000;
int mapper_pipes[4][2];
int reducer_pipes[26][2];
int letter_count[26];
void init_letter_count(void) {
int i;
for (i =0; i < 26; i++) {
letter_count[i] = 0;
}
}
void pipe_wrapper(int pipefd[]) {
int ret = pipe(pipefd);
if (ret == -1) {
perror("Error. Failed when trying to create pipes.");
exit(EXIT_FAILURE);
}
}
void create_mapper_pipes(void) {
int i;
for (i = 0; i < NUM_OF_MAPPERS; i++) {
pipe_wrapper(mapper_pipes[i]);
}
}
void create_reducer_pipes(void) {
int i;
for (i=0; i < NUM_OF_REDUCERS; i++) {
pipe_wrapper(reducer_pipes[i]);
}
}
// Prints an error msg and exits if one occurs. Else, returns the system call value.
int print_if_err(int syscall_val, const char* syscall_name) {
if (syscall_val < 0) {
perror(syscall_name);
exit(errno);
} else {
//No syscall error we can return
return syscall_val;
}
}
void send_chars_to_reducers(char * line) {
printf("SEND_CHARS_TO_REDUCERS read: %s\n\n", line);
int i;
int ob_size = 1;
int wlen = 0;
for (i = 0; i < strlen(line); i++) {
if (line[i] >= ALPHA_OFFSET && line[i] < ALPHA_OFFSET + LETTERS) {
int pipe_num = line[i] - ALPHA_OFFSET;
printf("SENDING %c TO REDUCER PIPE %d\n", line[i], pipe_num);
wlen = print_if_err(write(reducer_pipes[pipe_num][PIPE_WRITE_END], &line[i], ob_size), "write");
printf("WROTE %c to REDUCER %d\n", line[i], pipe_num);
}
}
printf("END OF SEND CHAR FOR LOOP");
close_reducer_pipes();
}
void close_reducer_pipes(void) {
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
print_if_err(close(reducer_pipes[i][PIPE_WRITE_END]), "close");
print_if_err(close(reducer_pipes[i][PIPE_READ_END]), "close");
}
}
void fork_mappers(void) {
/* Constants useful to all children */
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i=0; i<NUM_OF_MAPPERS; i++) {
pid_t mapper_pid = print_if_err(fork(), "fork");
if (mapper_pid == 0) {
int j;
for (j=0; j < NUM_OF_MAPPERS; j++) {
close(mapper_pipes[i][PIPE_WRITE_END]);
if (j != i) {
close(mapper_pipes[j][PIPE_READ_END]);
}
}
rlen = print_if_err(read(mapper_pipes[i][PIPE_READ_END], ibuf, 1000), "read");
send_chars_to_reducers(ibuf);
//printf("forked mapper%d read: %s\n\n", i, ibuf);
close(mapper_pipes[i][PIPE_READ_END]);
_exit(0);
}
}
}
void fork_reducers(void) {
printf("HELLLOOOO FROM REDUCER\n");
char ibuf[PIPE_BUFFER_SIZE]; // input pipe buffer
int rlen = 0;
int i;
for (i = 0; i < NUM_OF_REDUCERS; i++) {
pid_t reducer_pid = print_if_err(fork(), "fork");
if (reducer_pid == 0) {
while (1) {
rlen = print_if_err(read(reducer_pipes[i][PIPE_READ_END], ibuf, 1), "read");
printf("RLEN = %d\n", rlen);
if (rlen > 0) {
int letter_count_i = ibuf[0] - ALPHA_OFFSET;
printf("REDUCER #%d, read %s, letter_count_i = %d\n", i, ibuf, letter_count_i);
letter_count[letter_count_i]++;
} else {
break;
}
}
printf("REDUCER EXITING\n");
_exit(0);
}
}
}
void send_lines_to_mappers(void) {
int wlen = 0;
char obuf[PIPE_BUFFER_SIZE];
int ob_size;
int count = 0;
char buff[BUFFER_SIZE]; // a buffer for each line of the file
FILE *input_file = fopen("input.txt", "r");
// read the input file line by line
while(fgets(buff, BUFFER_SIZE, input_file) > 0) {
//printf("send_lines_to_mappers read: %s\n\n", buff);
ob_size = sizeof buff;
switch(count) {
case 0 :
write(mapper_pipes[0][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[0][PIPE_WRITE_END]);
close(mapper_pipes[0][PIPE_READ_END]);
break;
case 1 :
write(mapper_pipes[1][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[1][PIPE_WRITE_END]);
close(mapper_pipes[1][PIPE_READ_END]);
break;
case 2 :
write(mapper_pipes[2][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[2][PIPE_WRITE_END]);
close(mapper_pipes[2][PIPE_READ_END]);
break;
case 3 :
write(mapper_pipes[3][PIPE_WRITE_END], buff, ob_size);
close(mapper_pipes[3][PIPE_WRITE_END]);
close(mapper_pipes[3][PIPE_READ_END]);
break;
default :
printf("you did something wrong in send_lines_to_mappers loop");
}
count++;
}
fclose(input_file);
}
int main(void) {
init_letter_count();
// Setup the mapper pipes
create_mapper_pipes();
create_reducer_pipes();
fork_reducers();
fork_mappers();
send_lines_to_mappers();
return 0;
}
When you create a pipe, there are two ends ("file descriptors"), the reading end and the writing end.
When you fork(), the child process inherits ALL the open file descriptors, including both ends of ANY open pipe.
So, if you want:
[child1] >===pipe1===> [parent] >===pipe2===> [child2]
for example, then you have a several file descriptors to close.
In child1, you need to close the READ end of pipe1 AND BOTH ends of
pipe2.
In child2, you need to close the WRITE end of pipe2 and BOTH ends of
pipe1.
In the parent, after you are done forking, you need to close the
WRITE end of pipe1 and the READ end of pipe2.
As you have lots of pipes, you will have even more closing to do.
If you are not sure you have everything closed, the program lsof ("list open file-descriptors") can be helpful.

Resources