C - create two processes which can generate odd and even integers - c

I have this assignment where I have to create two processes and each process has to generate 50 integers which are odd or even.
Write a simple sequence-number system through which two processes, P1 and P2, can each obtain 50 unique integers, such that one receives all the odd and the other all the even numbers. Use the fork() call to create P1 and P2. Given a file, F, containing a single number, each process must perform the following steps:
a. Open F.
b. Read the sequence number N from the file.
c. Close F.
d. Output N and the process' PID (either on screen or test file).
e. Increment N by 1
f. Open F.
g. Write N to F.
h. Flush F.
i. Close F
As suggested by SO user I have created a loop in each process and ran the steps as mentioned above. But I am not sure if this approach is correct. I have asked my Teaching assistant for help and he suggested to do the same(using sleep call and waiting for a valid integer). But the thing is I can obtain the same results without using the sleep call. So I am not sure if I am applying the logic properly to code. Can someone please help?
This is my implementation:
void getUniqueNumbers() {
struct process p1;
struct process p2;
int numberFromFile;
pid_t pid = fork();
// Process 1
if (pid == 0) {
int p1Counter = 0;
p1.processId = getpid();
while(p1Counter < numLimit) {
numberFromFile = getNumberFromFile();
if (numberFromFile % 2 == 0) { // even
p1.numbers[p1Counter] = numberFromFile;
printf("N: %d, PID: %d\n", numberFromFile, p1.processId);
numberFromFile++;
writeNumberToFile(numberFromFile);
p1Counter++;
}
else {
sleep(1);
}
}
}
// Process 2
else if (pid > 0 ) {
int p2Counter = 0;
p2.processId = getpid();
while(p2Counter < numLimit) {
numberFromFile = getNumberFromFile();
if (numberFromFile % 2 != 0) { // odd
p2.numbers[p2Counter] = numberFromFile;
printf("N: %d, PID: %d\n", numberFromFile, p2.processId);
numberFromFile++;
writeNumberToFile(numberFromFile);
p2Counter++;
}
else {
sleep(1);
}
}
}
else {
printf("Error: Could not create process\n");
}
}
Read/Write functions:
// Returns the number included in user provided file
int getNumberFromFile() {
FILE *fp = fopen(fileName, "rb");
int num = 0;
if (fp != 0) {
char line[10];
if (fgets(line, sizeof(line), fp) != 0)
num = atoi(line);
fclose(fp);
}
return num;
}
// Writes a given number to the user provided file
void writeNumberToFile(int num) {
FILE *fp = fopen(fileName, "w");
if (fp != 0) {
fprintf(fp, "%d", num);
fclose(fp);
}
}

The code looks ok. It can be simplified a lot though.
void getUniqueNumbers()
{
struct process p; // We need only 1 structure
size_t counter = 0; // sample counter
int oddEven; // flag if we are parent
pid_t pid = fork(); // Fork here
if (-1 == pid)
{
abort(); // simply die on error
}
oddEven = 0 == pid ? 0 : 1;
p.processId = getpid(); // We are either child or parent.
while (counter < numLimit)
{
int numberFromFile = getNumberFromFile();
if ((numberFromFile & 1) == oddEven)
{
p.numbers[counter++] = numberFromFile;
printf("N: %d, PID: %ld\n", numberFromFile, (long)p.processId);
numberFromFile++;
writeNumberToFile(numberFromFile);
}
sleep(1); // sleep in both cases
// Extra check for parent: if child has died, we are in infinite
// loop, so check it here
if (0 != pid && counter < numLimit)
{
int status = 0;
if (waitpid(pid, &status, WNOHANG) > 0)
{
printf("Child exited with 0x%08X status\n", status);
break;
}
}
}
// wait till child process terminates
if (0 != pid)
{
int status = 0;
waitpid(pid, &status, 0);
printf("Child exited with 0x%08X status\n", status);
}
}
Also, the file reading/writing either should use file lock operations, or atomic file change. It is important to prevent potential errors like one thread is writing number 40006, and another one manages to read 400. Should not happen in real life though.
File locks are needed to prevent concurrent access to the same contents. It can be exclusive lock, or shared read exclusive write.
Atomic modifications are feature that enables to replace file contents atomically, regardless of how many operations it took to write the data. It is an alternative to keep data consistent.

Related

Pipe's related arguments to pass to a function?

I'm a beginner in C programming and I started learning about pipes today.
I need them because my program has to run up to 4 processes at the time, so to avoid creating more processes than those required, I have to use a shared variable between all of them to keep track how may can still be created.
I tried to simplify my program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void forking(int p, int pid);
int main(int argc, char *argv[])
{
int fd[2];
int p = 4; // Max number of processes that can run at the same time
int pid;
if(pipe(fd) == -1)
{
perror("pipe: ");
return 0;
}
//It will try the function forking 10 times to execute SOME CODE that
// changes everytime something operates on it
for(int i = 0; i < 10; i++)
{
forking(p, pid);
}
return 0;
}
void forking(int p, int pid)
{
if (p > 0) //We can create another process
{
p -= 1; // update the p before creating a child process
write(fd[1], &p, (sizeof(int)*3)); //Tell everyone about the update
pid = fork();
if (pid == 0)
{
//The child process turn to elaborate SOME CODE
// SOME CODE
// Then there will be a point where
// we will need to check if the p has been modified!
read(fd[0], &p, sizeof(int)*3);
//So that forking can decide whether we can create another process
// to operate on SOME OTHER CODE
forking(p, pid);
//Once we are done, we can terminate the child
//but first we'll need to update the process n° p
p += 1;
write(fd[1], &p, (sizeof(int)*3));
exit(0);
}
else if(pid > 1) //Father time
{
// check the updated value
//the father will do nothing
// since a process it's already on it (on the SOME CODE part)
return;
}
}
else
{
//else the father does SOME CODE itself
// SOME CODE
}
return;
}
My 2 doubts is whether I should pass something else to the function "forking" (which can be recursive), like "fd", or if it is okay to just leave the code like this, and whether this will have the desired result.
Hopefully I made myself clear enough.
EDIT 1:
void forking(int p, int pid, int *fd)
{
if (p > 0) //We can create another process
{
p -= 1; // update the p before creating a child process
write(fd[1], &p, (sizeof(int)*3)); //Tell everyone about the update
pid = fork();
if (pid == 0)
{
//The child process turn to elaborate SOME CODE
// SOME CODE
// Then there will be a point where
// we will need to check if the p has been modified!
read(fd[0], &p, sizeof(int)*3);
//So that forking can decide whether we can create another process
// to operate on SOME OTHER CODE
forking(p, pid, fd);
//Once we are done, we can terminate the child
//but first we'll need to update the process n° p
p += 1;
write(fd[1], &p, (sizeof(int)*3));
exit(0);
}
else if(pid > 1) //Father time
{
// check the updated value
//the father will do nothing
// since a process it's already on it (on the SOME CODE part)
return;
}
}
else
{
//else the father does SOME CODE itself
// SOME CODE
}
return;
}
Passing fd resulted as a success, now I'm wondering whether I should add pipe(fd) at the start of the forking program like so . . .
void forking(int p, int pid, int *fd)
{
if(pipe(fd) == -1)
{
perror("pipe: ");
return;
}
//Rest of the code
}

C Pipe between a parent and 2 children

I can not figure out why only 1 child sends data to parent (only the 1st child)..
When I do sleep(5) after the child1 sends data through pipe to parent then the 2nd child sends the same prime number to the parent.
Can someone help me?
//--------------------------Consts---------------------------------
#define NUM_OF_CHILDS 2
#define N 20
#define WIN 5
struct msg{
pid_t _pid;
int _prime;
};
//--------------------------Prototypes-----------------------------
bool is_prime(int num);
void terminate(pid_t child_pid[],int fd[2]);
void do_child(int fd[2]);
void print_pair(const int f_arr[],const int s_arr[]);
//--------------------------Main-------------------------------------
int main()
{
int f_arr[N] = {0},
s_arr[N] = {0},
ind, //running on children fork
count1 = 0,
count2 = 0,
victory1 = 0,
victory2 = 0,
min = 0;
int fd[2];
bool read1 = false,
read2 = false;
srand((unsigned)time(NULL));
pid_t child_pid [NUM_OF_CHILDS];//children pid status array
struct msg msg1;
if (pipe(fd) == -1)//pipe fd
{
perror("cannot open pipe");
exit(EXIT_FAILURE);
}
for(ind = 0; ind < NUM_OF_CHILDS; ind++)
{
child_pid[ind] = fork();// duplicate the current process
if (child_pid[ind] < 0)//fork failed
{
perror("Cannot fork()");
exit(EXIT_FAILURE);
}
if(child_pid[ind] == 0)/* child : sends message to parent*/
do_child(fd);
}
/* parent : receives message from child */
close(fd[1]); // close the write-end of the pipe
//read data from pipe
while(read(fd[0],&msg1,sizeof(struct msg)) > 0)
{
if(child_pid[0] == msg1._pid)
{
f_arr[count1++] = msg1._prime;
read1 = true;
}
else
{
s_arr[count2++] = msg1._prime;
read2 = true;
}
if(read1 && read2)
{
if(f_arr[min] > s_arr[min])
victory1++;
else if(f_arr[min] < s_arr[min])
victory2++;
read1 = false;
read2 = false;
min++;
}
if(victory1 == WIN || victory2 == WIN)
terminate(child_pid,fd);
}
close(fd[0]);// close the read-end of the pipe
print_pair(f_arr,s_arr);
return EXIT_SUCCESS ;
}
//---------------------------------------------------------------------
//checking if number is a prime number or not
//and return true or false
bool is_prime(int num)
{
int i;
if(num==0 || num==1 || num==2)
return false;
for(i=2;i<=num/2;i++)
{
//the number is not prime
if(num%i == 0)
return false;
}
//the number is prime
return true;
}
//----------------------------------------------------------------
void do_child(int fd[2])
{
struct msg message;
int num;
close(fd[0]);
while (1)
{
num = rand() % 1000;
if(is_prime(num))
{
message._prime = num;
message._pid = getpid();
write(fd[1], &message, sizeof(struct msg));
}
}
}
//----------------------------------------------------------------
void terminate(pid_t child_pid[],int fd[2])
{
int ind,
loop;
for(ind = 0; ind < NUM_OF_CHILDS; ind++)
{
close(fd[1]);
//first to give the process an opportunity to die gratefully before
//using SIGKILL
kill(child_pid[ind], SIGTERM);
bool died = false;
//It will give the process 5 seconds to die gracefully
for (loop = 0; loop < 5 && !died; ++loop)
{
int pid;
//the time the child process takes to close down gracefully.
sleep(1);
//to get the return status of that process and prevent zombie processes.
if (waitpid(child_pid[ind], &pid, WNOHANG) == child_pid[ind])
died = true;
}
//if SIGTERM did not killed the child do SIGKILL
if (!died)
{
int pid;
kill(child_pid[ind], SIGKILL);
waitpid(child_pid[ind], &pid, 0);// harvest the zombie
}
}
}
//------------------------------------------------------------------
void print_pair(const int f_arr[],const int s_arr[])
{
int ind;
for(ind = 0; ind < N; ind++)
{
if(f_arr[ind] == 0 && s_arr[ind] == 0)
break;
printf("(%d,%d)\n",f_arr[ind],s_arr[ind]);
}
}
First, the two child processes are generating the same pseudorandom sequence because they're starting with the same seed. To have any chance of different numbers, you need to seed them after the fork, and probably use something that changes more than once per second (the chance of the two of them having different values of time() is very small even if you moved the srand(time(NULL)) after the fork).
Second, you are receiving all the numbers from the first process because it has a head start. There's plenty of time to write to the pipe while the second process is being created. The parent doesn't start reading until after both children are created, so the first child fills the pipe buffer and then blocks. Pipe buffers are at least a few kilobytes.
Even when I slowed down the child process by making it print the numbers to stderr, the first one still generated hundreds of numbers before the second one got going.
So what happens in your main loop when there are hundreds of messages arriving from child 1 and none from child 2? Your f_arr array overflows because it only has room for 20. After that, anything can happen.
The simplest way to prevent that would be to check whether count1 == N before attempting to store a number into f_arr[count1++], and if so, just continue; to the next message. You should do the same for messages from the second child, even though it's not likely to happen.
This way you'll be accepting at most N messages from each child, and ignoring the rest. You'll need to add another end condition to the main loop: if both children have sent N messages, you need to stop.
Another way to go would be to use a separate pipe for each child and alternate reading from both pipes to keep them synchronized, but I have a feeling you were deliberately avoiding that.

Using multiple processes to read a file and sending numbers through pipe()

I have to use fork(2) to make as many children as inputted by the user.
Then I need them to split up the work reading a txt file of coordinate points comparing the distance between them to an inputted distance.
Then they add their count of how many points are within the distance given. Each child has to write their count to the pipe and the parent has to read each count and add it to the total and then print it out. Here is my code:
int main( int argc, char *argv[] ) {
int distance = atoi(argv[1]);
if ( argc != 3 || sscanf( argv[ 1 ], "%d", &distance ) != 1 )
fail( "usage: pairs <distance>" );
readPoints();
int workers = atoi(argv[2]);
// Compute the square of the distance bound, since that's what we'll
// need to compare against.
int dsq = distance * distance;
// Count up the number of nearby pairs of points.
int total = 0;
int fd[2]; // pipe
if ( pipe( fd ) != 0 ){
fail( "Can't create pipe" );
}
int pid; // child
int chNum; // child's number
int c;
for( chNum = 0; chNum < workers; chNum++){
c = 0;
pid = fork();
if ( pid == -1 ){ //failure
fail( "Can't create child process" );
}
if( pid ==0 ){ // it's a child
for ( int i =chNum; i < ptCount; i+=workers)
for ( int j = i + 1; j < ptCount; j++ ) {
// Check the squared distance.
int dx = ptList[ i ].x - ptList[ j ].x;
int dy = ptList[ i ].y - ptList[ j ].y;
if ( dx * dx + dy * dy <= dsq )
c++;
}
close(fd[READ]);
lockf(fd[WRITE], F_LOCK,0);
write(fd[WRITE], &c, sizeof(c));
lockf(fd[WRITE], F_ULOCK,0);
close(fd[WRITE]);
exit(0);
}
else if(pid>0){ // this is parent
int d;
close(fd[WRITE]);
read(fd[READ], &d, sizeof(d));
close(fd[READ]);
total = total + d;
}
}
if(pid>0){
wait(NULL);
printf( "Total: %d\n", total );
}
return 0;
}
I use a for loop to make the children with fork(2), and then I have them calculate the count and send it to the pipe to be read by the parent. The parent reads into d and adds it to total. I was wondering if I am using the pipe correctly to send each child's count to the parent and/or if I am forking correctly so it only comes from one parent. I am getting the wrong total count when I use more than 1 child.
If I use 1 child, the total result is 166428, which is correct, but when I use 4 for example, it gives me 164908. Can someone help me?
You're not doing pipe handling properly.
First off, you don't need to lock / unlock to write to and read from the pipe: writes that are less than PIPE_BUF bytes are guaranteed to be atomic. POSIX.1-2001 requires that PIPE_BUF is at least 512 bytes; since you're only writing sizeof(int) bytes at a time, you're safe (unless sizeof(int) is greater than or equal to 512, which is nonsense). See man limits.h, under Pathname Variable Values:
{PIPE_BUF}
Maximum number of bytes that is guaranteed to be atomic
when writing to a pipe. Minimum Acceptable Value: {_POSIX_PIPE_BUF}
That by itself simplifies the code and reduces unnecessary locking / unlocking overhead.
But the real issue is here:
else if (pid > 0) { // this is parent
int d;
close(fd[WRITE]);
read(fd[READ], &d, sizeof(d));
close(fd[READ]);
total = total + d;
}
You can't close fd[WRITE] inside the loop: consider what happens in the next iteration, when you fork the next process. The child process in the next loop will attempt to write to a file descriptor that has already been closed, so an error occurs (and write(2) fails with EBADF, but you never check the return value of write(2) so the code happily ignores the error). Plus, you attempt to close fd[WRITE] again and again, so close(2) will also return an error (which again, you ignore).
Similarly for read(2): if you close fd[READ], you can't read the results out of the pipe in the next iteration; read(2) will return an error and close(2) too.
(So the lesson is: do not ignore errors. If you had done error handling properly, you would have a pretty strong clue at what was going wrong)
You don't need to close. The child processes write exactly workers integers to the pipe; the parent process reads exactly workers integers from the pipe, so this is enough:
for (chNum = 0; chNum < workers; chNum++) {
c = 0;
pid = fork();
if (pid == -1)
fail("Can't create child process");
if (pid == 0) { // it's a child
for (int i = chNum; i < ptCount; i += workers) {
for (int j = i + 1; j < ptCount; j++) {
// Check the squared distance.
int dx = ptList[i].x - ptList[j].x;
int dy = ptList[i].y - ptList[j].y;
if (dx*dx + dy*dy <= dsq) {
c++;
}
}
}
ssize_t written = write(fd[WRITE], &c, sizeof(c));
if (written == -1)
perror("write error");
if (written != sizeof(c))
fail("Write failed on pipe");
exit(0);
}
else {
int d;
if (read(fd[READ], &d, sizeof(d)) != sizeof(d))
fail("Read error on pipe");
total += d;
}
}
The key point is to understand that you need to keep fd[READ] and fd[WRITE] open as long as you plan to fork new processes that will use the pipe.
Now, that fixes the problem, but you get a false sense of parallelism: reads in a pipe will block by default if no data is available. This means that on each iteration, the parent will not make progress until the corresponding child writes to the pipe. So you're not really parallelizing anything; the effect is the same as having the parent fork, wait for the child to terminate, read the result and add it to total, and then fork the next child (and repeat the cycle).
If you want true parallelism, you have to fork every process and only then start reading from the pipe. Something like this:
for (chNum = 0; chNum < workers; chNum++) {
c = 0;
pid = fork();
if (pid == -1)
fail("Can't create child process");
if (pid == 0) { // it's a child
for (int i = chNum; i < ptCount; i += workers) {
for (int j = i + 1; j < ptCount; j++) {
// Check the squared distance.
int dx = ptList[i].x - ptList[j].x;
int dy = ptList[i].y - ptList[j].y;
if (dx*dx + dy*dy <= dsq) {
c++;
}
}
}
ssize_t written = write(fd[WRITE], &c, sizeof(c));
if (written == -1)
perror("write error");
if (written != sizeof(c))
fail("Write failed on pipe");
exit(0);
}
}
if (close(fd[WRITE]) < 0)
fail("Error closing pipe's write channel");
int d;
ssize_t r;
while ((r = read(fd[READ], &d, sizeof(d))) > 0) {
if (r != sizeof(d))
fail("read error");
total += d;
}
Note that here we have to explicitly close the pipe's write channel before starting the reads; this is to avoid having the parent hang when no more child processes are actively writing to the pipe. Remember that a read will block as long as there is at least one process with the pipe's write channel open. If the parent process kept the write channel open, read(2) would never return because there is a chance that the parent himself could write to the pipe (even though we know it won't). So we have to close fd[WRITE].
Alternatively, since we know that there are exactly workers numbers to read from the pipe, we could just do this after the loop instead of closing the write channel:
int d;
int i;
for (i = 0; i < workers; i++) {
if (read(fd[READ], &d, sizeof(d)) != sizeof(d))
fail("Failed to read from pipe");
total += d;
}
A couple of other (unrelated) remarks:
The error message when the wrong arguments are given does not agree with the code. The code shows that distance is in argv[1] and workers is in argv[2], yet the error message passed to fail() seems to say that distance is in argv[2].
argv[1] is parsed twice as an integer: with atoi(3) and with sscanf(3). I'd stick to sscanf(3) since you can check the return value to make sure that parsing was successful.
workers is not validated and is converted with atoi(3). Errors are ignored. I'd suggest parsing it with sscanf(3) just like you did with distance and make sure that it is successful.
The correct type to store a pid is pid_t, not int. Please use the correct type (you might have to include sys/types.h in addition to unistd.h).
Here's the final version with all of this sorted out:
int main(int argc, char *argv[]) {
int distance;
int workers;
if (argc != 3 || sscanf(argv[1], "%d", &distance) != 1 || sscanf(argv[2], "%d", &workers) != 1)
fail("usage: <distance> <workers>");
readPoints();
// Compute the square of the distance bound, since that's what we'll
// need to compare against.
int dsq = distance * distance;
// Count up the number of nearby pairs of points.
int total = 0;
int fd[2]; // pipe
if (pipe(fd) != 0)
fail("Can't create pipe");
pid_t pid;
int chNum; // child's number
int c;
for (chNum = 0; chNum < workers; chNum++) {
c = 0;
pid = fork();
if (pid == -1)
fail("Can't create child process");
if (pid == 0) { // it's a child
for (int i = chNum; i < ptCount; i += workers) {
for (int j = i + 1; j < ptCount; j++) {
// Check the squared distance.
int dx = ptList[i].x - ptList[j].x;
int dy = ptList[i].y - ptList[j].y;
if (dx*dx + dy*dy <= dsq) {
c++;
}
}
}
ssize_t written = write(fd[WRITE], &c, sizeof(c));
if (written == -1)
perror("write error");
if (written != sizeof(c))
fail("Write failed on pipe");
exit(0);
}
}
if (close(fd[WRITE]) < 0)
fail("Error closing pipe's write channel");
int d;
ssize_t r;
while ((r = read(fd[READ], &d, sizeof(d))) > 0) {
if (r != sizeof(d))
fail("read error");
total += d;
}
printf("Total: %d\n", total);
return 0;
}

C program asking for user input multiple times

Writing a very basic C program that demonstrates shared memory. The program needs to keep calculating the sum of two inputs until the user does a ^C (not shown here).
What I have so far is that my parent captures user input, then tells the child to calculate the sum, which the parent then prints the sum (as the assignment suggests).
Attached is my code.
// Fork the process
while(1) {
// Declare a shared memory integer array
int *shared_ints = mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
int x;
int y;
shared_ints[3] = 0;
if((pid = fork()) < 0) {
printf("Fork error \n");
exit(-1);
} else if(pid > 0 && shared_ints[3] == 0) { // Parent code
// Ask user for first input
printf("Enter your first number:");
scanf("%d", &x);
printf("\n");
// Ask user for second input
printf("Enter your second number:");
scanf("%d", &y);
printf("\n");
// Assign first value to shared memory
shared_ints[0] = x;
// Assign second value to shared memory
shared_ints[1] = y;
// Tell child that it can compute the sum now
shared_ints[3] = 1;
// Trap parent in a while-loop while the child
// computes the sum
while(shared_ints[3] == 1);
// Child has completed calculating the sum and
// the parent can print the sum
if(shared_ints[3] == 2) {
printf("The sum is: %d", shared_ints[2]);
printf("\n");
}
} else { // Child code
// Wait for parent to accept input values
while(shared_ints[3] == 0);
// Calculate the sum
shared_ints[2] = shared_ints[0] + shared_ints[1];
// Tell parent sum has been calculated
shared_ints[3] = 2;
}
}
The sum calculation works until I go to the fourth-iteration of the sum calculation (this is the output):
Created shared memory object /my_shared_memory
Shared memory segment allocated correctly (16 bytes).
Enter your first number:1
Enter your second number:2
The sum is: 3
Enter your first number:Enter your first number:3
Enter your second number:4
The sum is: 7
Enter your first number:Enter your first number:5
Enter your second number:6
The sum is: 11
Enter your first number:Enter your first number:7
Enter your second number:8
Enter your second number:9
Enter your second number:
An interesting bug I see is that after I print the sum, the program asks for the first input twice as suggested here: Enter your first number:Enter your first number:3, and then in the fourth sum iteration, it asks for the second number several times before calculating the sum.
The trouble is that you're forking on each iteration of the outer while loop, so the first time around, you have one child, then you have a child that thinks it has grown up and is a parent (as well as the parent that knows it is a parent). And it gets worse as you continue.
Another problem is that you're allocating shared memory on each iteration of the outer while loop. I'm not sure it's exactly a memory leak, but it probably isn't a good idea.
To fix:
Move the mmap() and the fork() outside the while (1) loop.
The parent process will have a loop — in its own function, not all inside main(), please — that reads from the user, transfers to the child, reads the result from the child, and continues.
The child process will have a loop — also in its own function, please — that reads from the parent, calculates, and continues.
Make sure the child knows how to exit when the parent exits.
Ideally, use a synchronization mechanism other than busy waiting. A couple of mutexes or a couple of semaphores would be good. The processes would wait to be told there's work for them to do, rather than spinning their wheels (very fast) while waiting for the next task.
More or less working code
This uses a header "stderr.h" and functions err_setarg0() and err_syserr() from code I wrote because error reporting is crucial and these make it easy. You should be able to find code on SO from me with working versions of that header and those functions.
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "stderr.h"
static void be_childish(int *shared_ints);
static void be_parental(int *shared_ints);
int main(int argc, char **argv)
{
const char *file = "fidget";
int shared_seg_size = 4 * sizeof(int);
err_setarg0(argv[0]);
if (argc > 1)
file = argv[1];
int fd = open(file, O_RDWR|O_CREAT, 0600);
if (fd < 0)
err_syserr("Failed to open file %s for read/write\n", file);
/* Assume sizeof(int) == 4 */
if (write(fd, "abcdefghijklmnop", shared_seg_size) != shared_seg_size)
err_syserr("Failed to write %d bytes to %s\n", shared_seg_size, file);
int *shared_ints = mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shared_ints == 0)
err_syserr("Failed to mmap file %s\n", file);
shared_ints[3] = 0;
int pid;
if ((pid = fork()) == -1)
err_syserr("Failed to fork\n");
else if (pid == 0)
be_childish(shared_ints);
else
be_parental(shared_ints);
return 0;
}
static void be_childish(int *shared_ints)
{
while (1)
{
// Wait for parent to generate input values
while (shared_ints[3] == 0 || shared_ints[3] == 2)
{
printf("Child: %d\n", shared_ints[3]);
usleep(500000);
}
if (shared_ints[3] != 1)
{
printf("Child: exiting\n");
return;
}
// Calculate the sum
shared_ints[2] = shared_ints[0] + shared_ints[1];
printf("Child: calculated %d + %d = %d\n", shared_ints[0], shared_ints[1], shared_ints[2]);
// Tell parent sum has been calculated
shared_ints[3] = 2;
}
}
static void be_parental(int *shared_ints)
{
while (1)
{
int x;
int y;
// Ask user for first input
printf("Enter your first number:");
if (scanf("%d", &x) != 1)
{
printf("Parent: exiting\n");
shared_ints[3] = -1; /* Tell child to exit */
return;
}
printf("\n");
// Ask user for second input
printf("Enter your second number:");
if (scanf("%d", &y) != 1)
{
printf("Parent: exiting\n");
shared_ints[3] = -1; /* Tell child to exit */
return;
}
printf("\n");
// Assign first value to shared memory
shared_ints[0] = x;
// Assign second value to shared memory
shared_ints[1] = y;
// Tell child that it can compute the sum now
shared_ints[3] = 1;
// Trap parent in a while-loop while the child
// computes the sum
while (shared_ints[3] == 1)
{
printf("Parent: %d\n", shared_ints[3]);
usleep(500000);
}
// Child has completed calculating the sum and
// the parent can print the sum
if (shared_ints[3] == 2)
{
printf("The sum is: %d", shared_ints[2]);
printf("\n");
}
else
{
printf("Parent: unexpected control %d - exiting\n", shared_ints[2]);
shared_ints[3] = -1; /* Tell child to exit */
return;
}
}
}
This code has debugging in the busy-wait loops, and a delay of 0.5 seconds on each read cycle. You can tweak that to suit yourself, and lose the output once your sure it's working for you, too. Note that the code destroys a file fidget unless you specify an alternative name to be created/destroyed. It does not remove the file as it exits; it probably should.
Sample run
$ ./dualproc
Enter your first number:Child: 0
1
Enter your second number:Child: 0
2
Parent: 1
Child: calculated 1 + 2 = 3
Child: 2
The sum is: 3
Enter your first number:Child: 2
Child: 2
3
Enter your second number:Child: 2
4
Parent: 1
Child: calculated 3 + 4 = 7
Child: 2
The sum is: 7
Enter your first number:Child: 2
q
Parent: exiting
$ Child: exiting
$
The parent exited before the child did; no big surprise there. You could upgrade the code to use wait() to wait for the child to exit if you preferred.
NOTE: There is a problem here in a corner case where the parent quits and the child is still waiting for the parents input value - can happen if the user breaks the program when shared_ints[3] != 0
To demonstrate #Jonathan Leffler's excellent answer, here's my suggestion for a fix:
/* These are better declared outside the while loop */
// Declare a shared memory integer array
int *shared_ints = mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
int x;
int y;
// Fork the process
while(1) {
shared_ints[3] = 0;
if((pid = fork()) < 0) {
printf("Fork error \n");
exit(-1);
} else if(pid > 0 && shared_ints[3] == 0) { // Parent code
// Ask user for first input
printf("Enter your first number:");
scanf("%d", &x);
printf("\n");
// Ask user for second input
printf("Enter your second number:");
scanf("%d", &y);
printf("\n");
// Assign first value to shared memory
shared_ints[0] = x;
// Assign second value to shared memory
shared_ints[1] = y;
// Tell child that it can compute the sum now
shared_ints[3] = 1;
// Trap parent in a while-loop while the child
// computes the sum
while(shared_ints[3] == 1);
// Child has completed calculating the sum and
// the parent can print the sum
if(shared_ints[3] == 2) {
printf("The sum is: %d", shared_ints[2]);
printf("\n");
}
} else { // Child code
// Wait for parent to accept input values
while(shared_ints[3] == 0);
// Calculate the sum
shared_ints[2] = shared_ints[0] + shared_ints[1];
// Tell parent sum has been calculated
shared_ints[3] = 2;
/* Child process should finish, so it doesn't fork
and in the upper while loop. this is a fast way to do it */
exit(0);
}
}
At each iteration of the big while loop, the parent and child process are calling fork() in this line:
if((pid = fork()) < 0) {
You are repeatedly spawning more child processes after every iteration and can be creating unexpected interactions.

Reading from pipe issue

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.

Resources