My assignment is to pass integers entered on the command line and pass them through a pipe from parent to child where the integers can be added together and returned to the parent via reaping. All of my integers turn into the number 4 in the child, and the reaped value for sum always returns as the number 1.
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static int toChild[2];
static int toParent[2];
static int input;
static int output;
int main(int argc, char **argv)
{
pid_t pid;
int status;
int nInts = argc;
// set up pipe
pipe(toChild);
pipe(toParent);
// call fork()
pid = fork();
if (pid == 0) {
close(toChild[1]);
close(toParent[0]);
// -- running in child process --
int sum = 0;
// Receive characters from parent process via pipe
// one at a time, and count them.
// Return sum of numbers.
for (int i=1; i < nInts; i++) {
output = read(toChild[0], &input, sizeof(input));
sum += output;
}
return sum;
close(toChild[0]);
close(toParent[1]);
}
else {
close(toChild[0]);
close(toParent[1]);
// -- running in parent process --
// Send numbers (datatype: int, 4 bytes) from command line arguments
// starting with argv[1] one at a time through pipe to child process.
for (int i=1; i < nInts; i++) {
input = atoi(argv[i]);
write(toChild[1], &input, sizeof(input));
}
waitpid(pid, &status, 0);
if(WIFEXITED(status)){
// Wait for child process to return. Reap child process.
// Receive sum of numbers via the value returned when
// the child process is reaped.
printf("sum = %d\n", WIFEXITED(status));
}
close(toParent[0]);
close(toChild[1]);
return 0;
}
}
output = read(toChild[0], &input, sizeof(input));
sum += output;
You are assigning the return value of read to output. This is the number of bytes read, i.e. sizeof(input) which is 4 on your platform. So you are always increasing sum by 4.
You want:
ssize_t bytes_read = read(toChild[0], &input, sizeof(input));
//check that bytes_read == sizeof(input) here
sum += input;
Also:
printf("sum = %d\n", WIFEXITED(status));
WIFEXITED just says whether the process exited. Use WEXITSTATUS to get the exit status.
Related
I've read a few threads on here for information on this. I understand some but most of them are written in different methods. I just cant find sufficient information on how to return a value from a child process through a return statement. I blame myself for not looking hard enough, but i'm at a muddy puddle stuck. Any information is appreciated thanks.
My goal for this (school assignment) is to have a child process read information from the parent. The child will ten compute mathematically (addition) each value received from the parent, then send the final value back to the parent to print onto the screen.
RULES:
1. Can't use command line args inside of a child process only parent
2. All mathematical computation must be inside of child process.
3. No error checking is needed.
Here is some code of what i have:
int main(int argc, char **argv){
char buf[256];
int pipeCommunication[2];
pipe(pipeCommunication);
pid_t pid = fork();
if(pid == 0){
//inside child process
int sum = 0;
read(pipeCommunication[0], buf, sizeof(buf));
sum += atoi(buf);
return sum; //WHY DOES IT NOT RETURN THE VALUE OF SUM?
}else{
int sum = 0;
for(int i = 1; i<argc;i++){
write(pipeCommunication[0], argv[i], sizeof(argv);
wait(NULL);
}
printf("sum = %d\n", sum); //WHY CANT I SEE THE VALUE OF SUM FROM CHILD?
return 0;
}
}
Command line input would be: ./apprun 1 2 3
OUTPUT: 6
(added 1 + 2 + 3 = 6)
EDIT: I've realize that perhaps my write or read func need to cleared to allow another value to be read into the child process. Still trying to figure that out.
EDIT: I've completed the assignment and will post the result here if anyone wants to view the final code. Afterwards, this thread is completed.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#define SIZE argc-1
int main(int argc, char **argv)
{
int userInput[SIZE];
int temp;
int uiSize = sizeof(userInput)/sizeof(userInput[0]);
int pipeCom[2];
pipe(pipeCom);
printf("CS201 - Assignment 3 Regular - Jonathan Vazquez\n");
pid_t pid = fork();
if (pid == 0) {
int sum = 0;
close(pipeCom[1]);
for(int i = 0;i < uiSize; i++){
read(pipeCom[0], &temp, sizeof(temp));
sum += temp;
temp = 0;
}
return sum;
}else {
int sum = 0;
for(int i = 1; i < argc; i++){
userInput[i] = atoi(argv[i]);
}
close(pipeCom[0]);
for(int i = 1; i < uiSize+1;i++){
write(pipeCom[1], &userInput[i], sizeof(userInput));
}
int status;
wait(&status);
sum = WEXITSTATUS(status);
printf("sum = %d\n", sum);
return 0;
}
}
The return value of the child's main function (the 'sum' you are returning here) is accessable to the parent as the child's exit status. The exit status is limited to 8 bits (not a full integer), so it is generally only used to return a limited error code rather than a value, but it may be big enough for your purposes.
To get the child's exit code in the parent, you need to pass a pointer to a status variable to wait instead of NULL. Replace the wait(NULL) line with:
int status;
wait(&status);
sum = WEXITSTATUS(status);
Alternately (and recommended as 8 bits is usually not enough), you can create a second pipe going from the child back to the parent, and have the child write the sum to that pipe and have the parent read it.
How can I display the number of processes created?
(without using a formula)
for (i=0; i<3; i++)
fork();
count = count + 1;
printf("%d",count);
There are a number of ways to do this, and a good technique is to have each child write one byte into a file descriptor which the original process can read. Note that, for the sake of brevity, the following code contains absolutely no error checking. Also, we report only the number of spawned processes (7) rather than counting the original to get a count of 8:
int main(void) {
int fd[2];
int depth = 0; /* keep track of number of generations from original */
int i;
pipe(fd); /* create a pipe which will be inherited by all children */
for(i=0; i<3; i++) {
if(fork() == 0) { /* fork returns 0 in the child */
write(fd[1], &i, 1); /* write one byte into the pipe */
depth += 1;
}
}
close(fd[1]); /* exercise for the reader to learn why this is needed */
if( depth == 0 ) { /* original process */
i=0;
while(read(fd[0],&depth,1) != 0)
i += 1;
printf( "%d total processes spawned", i);
}
return 0;
}
Printing the count value out just once is the easy part. Because you can get the process pid before the for loop. And then get the pid again after the for loop and only print if the pids match. For the counting part, it depends on whether your child processes exit or not. If they exit the solution is easier. The below code demonstrates one possible solution if the child processes exit (for brevity have not done full error checking). The idea is that each child process counts its own children. Parent waits for each child to complete and adds in its count. Haven't had time to fully test/debug the program so there may be some errors. But hopefully gives you the general idea.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t before_pid, after_pid;
pid_t forked_pid;
int count;
int i;
int status;
before_pid = getpid();
count = 1; /* count self */
for (i = 0; i < 3; i++) {
forked_pid = fork();
if (forked_pid > 0) {
waitpid(forked_pid, &status, 0);
/* parent process - count child and descendents */
count += WEXITSTATUS(status);
} else {
/* Child process - init with self count */
count = 1;
}
}
after_pid = getpid();
if (after_pid == before_pid) {
printf("%d processes created\n", count);
}
return (count);
}
This is a program that was designed to take characters from the program call, pipe them one at a time to a child, count them in the child, return that value to the parent and print that value.
For some reason, the number of characters input isn't being displayed. It compiles without error and runs, but doesn't exit properly. This leads me to believe that the parent doesn't successfully reap the child and take the return value from it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
int main(int argc, char **argv)
{
int comm[2];
char buffer[50];
pid_t pid;
// set up pipe
pipe(comm);
// call fork()
pid = fork();
// code that runs in the child
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, 1) ==1) {
++nChars;
}
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
int size = 0;
printf("CS201 - Assignment 3 - \n");
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
close(comm[0]);
for (int i = 1; i < argc ; i++) {
size = strlen(argv[i]);
for (int j = 0; j < size; j++) {
write(comm[1], &argv[i][j], 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.
wait(&nChars);
printf("child counted %d chars\n", nChars/256);
return 0;
}
}
Your parent process needs to close the pipe after it's done writing.
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
close(comm[0]);
for (int i = 1; i < argc ; i++) {
size = strlen(argv[i]);
for (int j = 0; j < size; j++) {
write(comm[1], &argv[i][j], 1);
}
}
close(comm[1]); // <--- add this
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;
}
In the following code, I have two pipes, one, fd[] handles ferrying a range variable to the child processes. The other pipe rw[] is responsible for printing the results of the method. fd works correctly, but rw prints garbage. Both range and narc_num are long and I have sucessfully printed a string and a char through the rw pipe. Any ideas? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <string.h>
/**
* process propigating version of narcisstic base-10 number generator
**/
/**
* A Narcissistic number is a number where all of its digits, when raised to the power n where n is the number of digits in its number, equla the number itseld.
* examples:
* 2^1 = 2
**/
void isNarcissisticNumber(int rw[], long min, long max){
// printf("min %ld max %ld\n", min, max);
long n;
for(n = min; n <= max; n++){
long num = n;
int digits = floor(log10(num)) + 1;
int digit_arr[digits];
long narc_num = 0;
int index = 0;
do{
digit_arr[index++] = num%10;
num /= 10;
}while(num > 0);
index = 0;
for(index; index < digits; index++){
narc_num += pow(digit_arr[index], digits);
}
if(narc_num == n){
printf("%ld\n", n);
// parent: writing only, so close read-descriptor.
close(rw[0]);
write(rw[1], &n, sizeof(long));
// close the write descriptor
close(rw[1]);
}
}
}
int main(int argc, // Number of strings in array argv
char *argv[]){ // Array of command-line argument strings)
//check that there is only one passed in parameter in addition to the program name at argv[0]
if(argc != 2){
printf("Args found: %d. 1 arg required\n", argc);
return;
}
//check that argv passed in is an int
if(!atoi(argv[1])){
printf("argument shoud be the # of processes to proc.\n");
return;
}
int num_processes = atoi(argv[1]);
//counter for narcissistic numbers
long offset = 10000;
long range= -offset;
//file pipe
int fd[2];
//printing pipe
int rw[2];
int n = 0;
long output;
while(n < num_processes){ // -1 offset to line up array index with num_processes arg
pipe(rw);
pipe(fd);
pid_t process = fork();
pid_t child_process;
int status;
if(process == 0){ //chid process --> execute program
child_process = process;
/* Duplicate the input side of pipe to stdin */
// chid: reading only, so close the write-descriptor
close(fd[1]);
read(fd[0], &range, sizeof(range));
close(fd[0]);
isNarcissisticNumber(rw, range, range+offset-1);
}else if(process != 0){
// parent: writing only, so close read-descriptor.
close(fd[0]);
range += offset;
write(fd[1], &range, sizeof(range));
// close the write descriptor
close(fd[1]);
// for the current child process to complete its routine befire checking for output
wait(&child_process);
//read from the printing pipe
close(rw[1]);
while(read(rw[0], &output, sizeof(long))){
printf("printer %ld\n", output);
}
close(rw[0]);
}else{ //failed to fork
printf("process failed to fork!\n");
return -1;
}
n++;
}
}
EDIT #1: while that made the parent only check after a child completed, it doesn't fix the output of the pipe, which is now just 0 even as the printf shows otherwise.
I'm not sure this will fix all the problems but you definitely have a logic issue. In your computation routine you can write zero or more longs to the output. In your print (parent) routine, you expect exactly one value to come through. So if nothing is sent, your read will fail. If multiple values are sent, you only read the first one. First fix would be to check your return value from read and also loop on it.
Note also - probably also a good idea to wait() on your child process.