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.
Related
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);
}
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.
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.
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);
}
I am writing on a pipe 10 integers, so i call write 10 times and then i want to call read pipe only once and store the written integers into an array of size 10 and after that add all the integers from the array into a total sum. The problem is that i get only 9 integers after reading. What i am doing wrong?
int main()
{
int fd[2];
int total = 0;
int result;
int nbytes;
int child;
int subVector;
int written;
static int readSum[P];
int partialSum;
if(pipe(fd) < 0){
perror("pipe");
}
for(child = 0; child < P; child++){
if((pid[child] = fork()) < 0){
perror("fork");
exit(1);
}
else if(pid[child] == 0){
close(fd[0]);
partialSum = getSubvectorSum(elementsList,child,P,SIZE);
//printf("Partial sum: %d by child #%d\n",partialSum,getpid());
written = write(fd[1],&partialSum,sizeof partialSum);
//printf("Child #%d has written: %d bytes.\n",getpid(),written);
if(written == 0){
printf("Writting not performed.");
}
close(fd[1]);
exit(0);
}
}
close(fd[1]);
int status = 0;
nbytes = read(fd[0],&readSum,sizeof readSum);
printf("Parent reads %d bytes\n",nbytes);
if(nbytes > 0){
for(child =0;child<P;child++){
total += readSum[child];
printf("Partial sum in father: %d\n",readSum[child]);
}
}
else{
printf("Failed to read.");
}
}
You are ignoring the wisdom of the sage Rolling Stones and not accepting that you can't always get what you want but sometimes you get what you need.
(1) There is no guarantee all your children have run and written to the pipe before the parent tries to read.
(2) There is no guarantee even if (1) did take place that your read would return all 10 integers in one read. read can (and often will) return less than you ask for.
One way to cover this is to have your parent wait on its children so you know they completed and then to read in a loop until you read everything you need.
http://linux.die.net/man/2/read
Read returns available data, not the requested amount, use cycle and check return value on each iteration.