-3

While preparing for an exam, I've had this piece of code:

int y;
int main()
{
  pid_t id;
  int i,j;
  y=0;
  id=fork();
  if(id==0){
    for(i=0;i<5;i++){
       y=y+2;
     }
  }else{
     for(j=0;j<10;j++){
       y=y+3;
     }
  }
  wait(NULL);
}

Assume that y is in shared memory.

I need to find the minimum possible value of y.

I know the answer is 10, but I can't figure out why.

Since the parent process and the child process both have to add value to y, it doesn't matter in which order they'll run, the result stays the same which is 40.

The only way for y to be 10 is only if the parent process will die before entering the for loop.

I would love for some explanation why the minimum value of y could be 10.

Thanks in advance!

edit: The code doesn't have any evidence of y being in a shared memory but I have to assume that for understanding purposes

  • 2
    y is separate for each process. – stark Jun 22 '21 at 10:07
  • The code you've shown does not have `y` in shared memory. Does the exam actually say that `y` is in shared memory? Or did you somehow decide that `y` is in shared memory? – user3386109 Jun 22 '21 at 10:12
  • 2
    *I know the answer is 10* No it's not. If `y` is in shared memory, simultaneous updates are not guaranteed to produce any value - it's a [race condition](https://stackoverflow.com/questions/34510/what-is-a-race-condition). – Andrew Henle Jun 22 '21 at 10:17
  • It's not the full code, Iv'e been given this piece of code and under it they told me that y is in shared memory – Ariel Turchinsky Jun 22 '21 at 10:19
  • 1
    Indent properly. There's no such thing as `for .. else` – klutt Jun 22 '21 at 10:27

3 Answers3

3

The question is flawed, not the least because it will not compile due to a missing }, even when the missing header includes are inserted.

The question poser’s reasoning is:

  • In the child process, y=y+2; may execute by loading y, adding 2, and storing the sum to y.
  • Between loading y and storing to y in the above, the parent process may execute y=y+3;. If so, the execution of y=y+3; will have no lasting effect, because, when the child stores to y, it will overwrite the change caused by y=y+3;.
  • Each of the ten executions of y=y+3; may occur completely within single executions of y=y+2;. For example, three executions of y=y+3; may occur inside the first execution of y=y+2;, another one may occur inside the second execution, and six may occur inside the third execution.
  • Therefore, all ten executions of y=y+3; may have no net effect, while the five executions of y=y+2; do have their cumulative effects, resulting in y being 10.

Now, we can assume that y is in shared memory, since the title of this post indicates it is. The code as shown will not make this so, but we can hypothesize that the code is rewritten to create a shared memory segment and to use some object inside it instead of using the y shown. So that is a minor flaw in the problem.

However, another flaw is that the C standard does not guarantee what happens when an int object is accessed simultaneously by multiple processes. Generally, when a non-atomic object is accessed by multiple processes, updates to the value of the object can not only be lost but can be mixed, resulting in corruption of the value of the object, so that the result is neither the value that one process attempted to store nor the value that another process attempted to store.

This is unlikely to occur for an int object on modern hardware, but the question should have specified its conditions more clearly.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    Agree with your reasoning that the question is flawed. But with the rest of the answer, how do we predict the order in which two independent processes are scheduled? If `y` is indeed somehow shared memory, this is a text-book race-condition, isn't it? – th33lf Jun 22 '21 at 10:22
  • 2
    @th33lf: Nothing in this answer says that execution occurs in any particular order or is predictable. It indicates other orderings are possible and states that the updates can corrupt the value. – Eric Postpischil Jun 22 '21 at 10:26
2

At the fork(), your program splits into two processes and each runs a different for loop:

Child (id = 0):

for(i=0;i<5;i++)
{
     y=y+2;
}

Here, y is incremented by 2, five times in a loop, so the end result is 10

Parent (id != 0):

for(j=0;j<10;j++)
{
    y=y+3;
}

Here, y is incremented by 3, ten times in a loop, resulting in 30

What you should understand here is that from the point where the fork() happens, there are two different copies of y, one in the parent and other in the child process. These two not the same memory location like you expect.

So the minimum value of y is in the child process, which happens to be 10.

PS: Although you say the variable 'y' is in shared memory, I see no evidence of that in the code, since it seems to be just a normal global int, hence my answer. If it is somehow in shared memory, it might result in predictable behaviour on a particular platform, but looking at it as a piece of C code, there is no way to reason about how it will execute and hence it is a race-condition. Like others have also mentioned in their answers, the question itself is flawed.

th33lf
  • 2,177
  • 11
  • 15
  • Sorry if wasn't clear, you need to assume that y is in shared memory even if it has no evidence of that (That's how the question is written in the book). – Ariel Turchinsky Jun 22 '21 at 10:27
  • 2
    @ArielTurchinsky Which book is this? It feels like the question itself is wrong. You would never want to access shared memory in this manner because the outcome is unpredictable. – th33lf Jun 22 '21 at 10:36
  • @th33lf: How can a book teach that accessing shared memory in this manner is wrong without explaining why by showing an example? – Eric Postpischil Jun 22 '21 at 11:33
  • @EricPostpischil Well, that could well be the intention. Though asking what would be the value seems to kind of lead the reader towards the expectation that there is one right answer, which is not the case. Of course, without any more info about the book, we're just speculating. – th33lf Jun 22 '21 at 11:42
  • @th33lf: If `y` is in shared memory and is atomic, there is one right answer: 10 is the minimum possible value `y` could have after the loops. – Eric Postpischil Jun 22 '21 at 11:45
  • @EricPostpischil Not necessarily. First of all, the question does not mention atomicity. Secondly, if access to `y` is atomic and the code is compiled for a platform that supports an atomic fetch and add instruction, then the final value would be consistently 40 after both loops execute. The truth is we can't predict without more information! – th33lf Jun 22 '21 at 13:35
  • @th33lf: I did not say atomic fetch and add, just atomic. The posted question did not relate all conditions of the question, but we can see it assumes any single access (load or store) is atomic, in that it does not corrupt the value. In this case, the minimum is ten. – Eric Postpischil Jun 22 '21 at 15:25
2

man fork

fork() creates a new process by duplicating the calling process.

The child process and the parent process run in separate memory spaces.

At the time of fork() both memory spaces have the same content.

Memory writes, ..., performed by one of the processes do not affect the other.

Considering the above, how comes that you think that "The variable y is in shared memory." and that a change in either process could affect the value in the other.

This code runs in your child process

for(i=0;i<5;i++){
    y=y+2;
}

and this in the parent process

for(j=0;j<10;j++){
    y=y+3;
}

a printf in the child process would present a different output than in the parent process.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11