Can the atomic builtins be used across multiple processes?

858 Views Asked by At

I'm getting back into C from .NET so please forgive my code, but I'm trying to implement the atomic builtin incrementer across an existing multi process program.

I wrote up a test program, and I can't get it to work. It increments to 5 correctly, but each child increments the value to 6, rather than collectively incrementing it to 10. Monitor displays 5.

I've tried various changes using a global int versus passing the static int from main to the child, but same result. Any help is appreciated, thank you.

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <sys/types.h>
  4 #include <stdlib.h>
  5 #include <unistd.h>
  6 #include "list.h"
  7 
  8 #define N 5
  9 static int globalcount = 0;
 10 
 11 void Monitor()
 12 {
 13     sleep(1);
 14     printf("Monitor Value %d\n", globalcount);
 15 }
 16 
 17 void Child()
 18 {   
 19     int value = __sync_add_and_fetch(&globalcount, 1);
 20     printf("Child Value %d\n", value);
 21 }
 22 
 23 int main(int argc, char** argv)
 24 {
 25     int i;
 26     int value;
 27     static int count = 0;
 28     pid_t pid[N];
 29     pid_t pidkey;
 30 
 31     for (i = 0; i < N; ++i) {
 32         value = __sync_add_and_fetch(&globalcount, 1);
 33         printf("Value %d\n", value);
 34     }
 35     printf("\n\n\n");
 36 
 37     if ((pidkey = fork()) == 0) {
 38         Monitor();
 39     } else if (pidkey > 0) {
 40         for (i = 0; i < N; i++)
 41         {
 42             if ((pid[i] = fork()) == 0) {
 43                 Child();
 44                 break;
 45             }
 46         }
 47     }
 48     return 0;
 49 }   
3

There are 3 best solutions below

3
On BEST ANSWER

If memory serves me correctly, when you fork() your process, the child process gets a copy of the variables, or rather, the variables are copy-on-write. That is, you essentially refer to the same data until you try and change it. What you are trying to accomplish requires more than just a static variable declared at the top of your code. You need to look at using shared memory so that you can share the variable(s) across process spaces. Since that is something that would take a long time to get into and really is not a 5-line answer, I will have to come back and edit this later with more detail. However, if you look up the shm_get function in your man pages (along with the various other shm_* functions that go along with it), the documentation is quite extensive. There are also a number of tutorials out there on the web: search for "POSIX IPC shared memory tutorial example" and you should get a variety of hits describing how to do it.

0
On

These atomic operations are not part of the C standard, yet, they are planed to be part of the next standard, though.

The ones you seem to use look as if you are using gcc? You'd really have to look up the documentation of

  • your compiler for the atomic primitives, and how they behave w.r.t to thread shared memory (the same address space) and process shared memory (different virtual addresses point to the same "physical" memory).
  • your OS (unix?) to know on how memory is shared (or not) after a fork.
0
On

As Will says, the child processes created by fork() are independent of their parent (and each other). They each conceptually have their own private copy of data allocated in normal ways.

If you wish to share memory between the processes, you must explicitly created a shared memory region, before you call fork():

int *globalcount = mmap(0, sizeof *globalcount, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*globalcount = 0;