We need to tell the outcome of the following C program:
main()
{
int pid, k, som;
som = 0; k = 2;
pid = fork();
if(pid == 0)
k=5;
else
wait(0);
for(int i = 1; i <= k; i++)
som += i;
printf("%d", som);
}
My first expectation is 3. When a the fork call is made, the memory of the process is copied, and both programs go running. The child process then executes, but k still equals 2. So at the end, it executes 1 + 2 = 3;
But when this program is executed, it outputs 153. I haven't got the nearest clue why it outputs that.
Can anyone tell why?
The reason why is you have 2 processes printing out to the same console. "fork" is a unix/linux command that is called once and returns twice. One of the returns will be in the original process which called fork and will return the PID of the child process that was spawned. The second return will be 0 and this indicates it is the child process.
One of the programs, the child i believe, executes first and calculates 15 as the value and prints it to the console last. The parent program executes second because of the wait(0) and produces the value 3.
15 is printed by child, and 3 by parent.
A is parent, B is the child, here are the important lines:
A: pid = fork(); // returns 0 for the child process
A: wait(0);
B: k = 5;
B: for(int i = 1; i <= k; i++) som += i; // som = 15
B: printf("%d", som); // prints 15, B finishes, goes back to A
A: for(int i = 1; i <= k; i++) som += i; // som = 3
A: printf("%d", som); // prints 3
There's no newline being printed between the values so the parent's answer appears right after the child's answer.
Jared's correct about the cause of the values.
Related
The C script is supposed to take x amount of CPU bound forks and x amount of IO bound forks, so then lets say 10 total processes if you there's 5 of each. If I fork 10 times, then 5 of those should go to working on the CPU bound "fake work" and 5 of those should go to the IO bound "fake work". Waitstats is a custom function that serves the purpose of wait while also displaying rtime and wtime.
My problem is that I've tried multiple configurations and I'm not sure how to get the Process Number printf to correctly print, only 10 times, if there's only 10 forks? I also feel as if I'm not doing my fake work correctly for the CPU/IO bound work.
Any help here would be appreciated!
`
int main(int argc, char* argv[])
{
int cpuNum = atoi(argv[2]);
int ioNum = atoi(argv[4]);
int const MAX_PROC = cpuNum + ioNum;
printf("\nMax Proc %d", MAX_PROC);
int totRunTime = 0;
int totWaitTime = 0;
uint rTime = 0;
uint wTime = 0;
int pid = 0;
//Create Max_Proc Forks
for(int n=0; n < MAX_PROC; n++)
{
pid = fork();
//If Child, Exceute Command
if(pid == 0)
{
break;
}
}
if (cpuNum > 0) {
//CPU Busy Work
for (volatile int i = 0; i < 1000000000; i++){}
cpuNum--;
}
else if (ioNum > 0) {
//IO Busy Work
sleep(200);
ioNum--;
}
for(int p=0; p < MAX_PROC; p++)
{
printf("\n Process %d finished", p);
if(waitStats(0, &rTime, &wTime) >= 0)
{
totRunTime += rTime;
totWaitTime += wTime;
}
}
printf("\nAverage rtime %d, wtime %d", rTime, wTime);
exit(0);
}
`
I've tried multiple configurations, but can't seem to get the printf to print the correct process/fork number. For instance forking 10 times would mean I would need to printf every time one of those forks finished their task (10 total times).
The code shown doesn't print pids, so I'm assuming you mean "process number" as in 1st child, 2nd child etc.
Every one of your processes is running this:
for(int p=0; p < MAX_PROC; p++)
{
printf("\n Process %d finished", p);
...
So it looks like each process will print the numbers 0 .. MAX_PROC-1 (with no indication of which pid is printing)
Have you tried putting the waitStats for loop inside of your "Create Max_Proc Forks" for loop? So then basically everything should be inside of the first loop, probably giving you a good way to keep track of the process number?
I have to find the biggest value in an array of a 1000 numbers with 10 child processes (so that every one of them only checks a hundred values), and the parent only has to collect the data.
I'm already done with the whole thing, but I'm stuck at reading the values.
Here's the code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int main(){
int array[1000];
int i, j;
int pids[10];
int searchminindex;
int searchmaxindex;
int maxindex;
srand(time(NULL));
//fill up array with random numbers
for(i = 0; i < 1000; i++)
{
tomb[i] = random() % 5000;
}
//create 10 child processes
for (i = 0; i < 10; i++) {
if ((pids[i] = fork()) < 0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
searchminindex = i * 100;
searchmaxindex = (i+1) * 100;
//finding the biggest value
maxindex = searchminindex;
for(j = searchminindex+1; j < maxindex; j++) {
if( array[maxindex] < array[j])
maxindex = j;
}
}
}
for(i = 0; i < 10; i++){
//here's where I'd read the return values of the subarrays
}
return 0;
}
I've tried using pipes and also using WEXITSTATUS, but I'm really confused and don't know where to close one end of the pipe and things like that, and with WEXITSTATUS I'm completely lost.
Any way you could help?
You need to test the pid returned from fork, and branch your code so your main process doesn't act like a child, and so that your children don't spawn children of their own. Once that's taken care of...
An alternative to mmap or setting up shared memory at all is to use WEXITSTATUS. According to the man page, it'll only return the least significant 8 bits, so if your return values can be greater than 127, this is likely not your best option. Can be made to work up to 255, but be careful about signedness of char, it's not standard.
int returned_values[10];
for(int i = 0; i < 10; ++i)
{
int status;
wait(&status);
if(WIFEXITED(status))
returned_values[i] = WEXITSTATUS(status);
else {
//Do something more meaningful here
//This means a child received a signal, or any of the other ways wait returns other than a child exiting.
--i;
}
You need to test the pid returned from fork, and branch your code so your main process doesn't act like a child, and so that your children don't spawn children of their own. Once that's taken care of...
Sharing memory between forked processes is explained well here
I would use mmap to create shared memory between the processes, you'll need to specify for each process where to put it's result, then use wait to determine when all children have exited, and a good program would evaluate the exit status and inform the user if any child exited abnormally.
Don't forget to clean up the shared memory before the parent exits.
Currently working on some homework and having a hard time. The goal is to generate 100,000 numbers and add them all together by dividing the work into 10 processes (10,000 numbers each)
I think I've figured out how to fork processes (hopefully), but using Pipe() to relay the subtotals from each child process is not working... the program below returns 44901 for each child process and 449010 for the running total.
I'm struggling hard but I feel like this is something simple I should be able to understand.
main()
{
int i;
pid_t pid;
int status = 0;
int fd[2];
int runningTotal = 0;
pipe(fd);
int t;
int r;
for (i = 0; i < 10; i++) {
pid = fork();
if (pid == 0){
close(fd[0]);
t = ChildProcess();
write(fd[1], &t, sizeof(t));
exit(0);
}
close(fd[1]);
read(fd[0], &r, sizeof(r));
runningTotal = runningTotal + r;
wait(&status);
}
printf("%i\n", runningTotal);
}
int ChildProcess() {
int i;
int total = 0;
int r = 0;
for (i = 0; i < 10000; i++) {
r = rand() % 10; // 0 to 10
total = total + r;
}
printf("%i\n", total);
return total;
}
Ordinarily, one would use a separate pipe for each child, for otherwise it's impossible for the parent to know from which process the data it reads comes. I don't think that's so much of an issue in this particular case, though, because here, you actually don't care. Although it still makes me cringe a bit, I think you indeed can get away with just one pipe for this particular task.
In fact, I don't think your problem is with the pipe at all. It is with rand(). All child processes compute exactly the same sequence of (pseudo-)random numbers because they all use the same (default) seed. If you want to produce different sequences of numbers, then you need to call srand() in each child process, giving a different seed in each one. The sequence of numbers rand() will generate is completely determined by the seed with which it starts.
Note, too, that if the system's random number generator is any good at all, then all the sums computed by the various processes should be very close to each other, and to the result you reported. This is a consequence of the Central Limit Theorem in statistics, but you can think of it simply as the larger results balancing the smaller ones on average. There's probably a slight bias arising from calculating the remainder mod 10.
Initial diagnosis
If your concern is that the children are all producing the same values, then the problem is that they're all using the same random sequence because you don't call srand() anywhere. You need to call it once per child, with a different seed for each child.
It isn't 100% reliable, but you could probably get away with srand(time(0) + getpid()); in each child — or even just getpid() since those values are guaranteed to be different.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int ChildProcess(void)
{
int total = 0;
srand(time(0) + getpid());
for (int i = 0; i < 10000; i++)
{
int r = rand() % 10; // 0 to 9 (not 10).
total = total + r;
}
printf("%i\n", total);
return total;
}
Further scrutiny
Actually, on closer examination, there's another problem. The parent process closes the write end of the pipe after forking the first child, so the subsequent children don't have a usable file descriptor to use. The read value will always be the one from the first child. So, you need to do more serious work.
int main(void)
{
int fd[2];
pipe(fd); // Missing error check
for (int i = 0; i < 10; i++) {
pid_t pid = fork();
if (pid == 0){
close(fd[0]);
int t = ChildProcess();
write(fd[1], &t, sizeof(t)); // Missing error check?
exit(0);
}
// Print PID here? Error check?
}
close(fd[1]);
int r;
int runningTotal = 0;
while (read(fd[0], &r, sizeof(r)) > 0) // Debugging opportunities here
runningTotal = runningTotal + r;
while (wait(0) > 0) // Lots of debugging opportunities here
;
printf("%i\n", runningTotal);
return 0;
}
given this code: (an excerpt from the posted code)
for (i = 0; i < 10; i++) {
pid = fork();
if (pid == 0){
close(fd[0]);
t = ChildProcess();
write(fd[1], &t, sizeof(t));
exit(0);
}
close(fd[1]);
read(fd[0], &r, sizeof(r));
runningTotal = runningTotal + r;
wait(&status);
}
there is a sequence problem.
When the parent closes the fd[1] during the first iteration of the loop, that file descriptor does not 'magically' open again for the next iteration of the loop.
The code for the parent, in the loop, needs to check the returned value from the call to read() to assure the operation was successful. (it probably was not successful after the first iteration through the loop, so the variable 'r' will be unchanged.
How come in the below program the local variable of parent process is acting as a shared variable between three child processes.
int main()
{
int turn = 0;
int i;
for (i = 0; i < 3; i++)
{
if (fork() == 0)
{
int me = i;
while (turn != me)
/*do nothing*/ ;
// my turn
printf("Process %d ran\n", me);
turn++;
}
}
return 0;
}
Output:
Process 0 ran
Process 1 ran
Process 2 ran
But according to me the last two processes should hang as the value of turn should never change for them.
Also if i put a exit(0); after turn++, I am returned immediately to my shell prompt with only one line of output i.e:
Process 0 ran
But still the other two processes keep running in the background and no output by any of the other two processes.
What's going on:
main process is 0.
process 0 calls fork. i = 0;
process 0 returns from fork = 1;
process 0 calls fork. i = 1;
process 0 returns from fork = 2;
process 0 calls fork. i = 2;
process 0 returns from fork = 3;
process 0 exists;
process 1 returns from fork. i = 0;
process 1 hits the while loop turn = 0, i = 0, me = 0, while loop exists;
process 1 calls printf.
process 1 increments turn, turn = 1;
process 1 goes back to the for loop;
process 1 calls fork, i = 1;
process 1 returns from fork = 4;
process 1 calls fork, i = 2;
process 1 returns from fork = 5;
process 1 exists;
process 2 returns from fork. i = 1;
process 2 hits the while loop turn = 0, i = 1, me = 0, while loop spins forever;
process 3 returns from fork, i = 2;
process 3 hits the while loop turn = 0, i = 2, me = 0, while loop spins forever;
process 4 (spawned from process 1) returns from fork, i = 1, turn = 1 (inherited from process 1).
process 4 hits the while loop turn = 1, i = 1, me = 1, while loop exits;
process 4 calls printf;
process 4 increments turn, turn = 2;
process 4 goes back to the for loop;
process 4 calls fork, i = 2, turn = 2;
process 4 returns from fork = 6;
process 4 exits;
process 5 (spawned from process 1) return from fork, i = 2, turn = 1 (inherited from process 1)
process 5 hits the while loop turn = 1, i = 2, me = 2, while loop spins forever;
process 6 (spawned from process 4) returns from fork i = 2, turn = 2 (inherited from process 4)
process 6 hits the while loop turn = 2, i = 2, me = 2, while loop exists;
process 6 calls printf;
process 6 drops out of the for loop
process 6 exits;
Basically, you need to remember that all processes you will continue running the for loop, not just the main one. After that it's not too hard to figure out what's going on. You spawn 6 processes in total and three of them will have the right state of i and turn.
Refactor your code like this:
#include <unistd.h>
#include <stdio.h>
int main()
{
int turn = 0;
int i;
for (i = 0; i < 3; i++)
{
printf("forking i = %d, turn = %d\n", i, turn);
if (fork() == 0)
{
int me = i;
while (turn != me)
/*do nothing*/ ;
// my turn
printf("Process %d ran\n", me);
turn++;
}
}
return 0;
}
It may come as a shock to you but as Art's refactoring above shows pretty clearly your code will spawn 6 processes. Putting some more printfs in there should get your understand what's really going on.
Variable declared before fork() is shared for child processes. You may check it by printing &turn in loop. It will be same.
I want to write a program with vfork() and parent creates n children, I want to insert number of sons with parameter. And then I want to sum the number of sons for example:
./sum 4
The sum of the child: 10
The sum of the parent: 10
(1+2+3+4)
This is the small code I came up, but I get infinite loop.
int n = atoi(argv[1]);
int i = 1;
pid_t pid;
int sumchild = 0;
int sumparent = 0;
while(i <= n){
pid = vfork();
if(pid == 0){
sumchild = sumchild + i;
}
i++;
}
printf("The sum of the child: %i ", sumchild);
sumparent = (1 + n) * (n / 2);
printf("The sum of the parent: %i \n", sumparent);
I heard that you don't need wait() like in fork(), but I don't know why do I get infinite loop here.
How should I use vfork()?
Did I even write the code right or I made some mistakes?
The following code
pid = vfork();
if(pid == 0){
sumchild = sumchild + i;
will cause undefined behavior, according to vfork:
The vfork() function has the same effect as fork(2), except that the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions.