3

I come from a C# background and I have a bit of a tough time with concurrency in C. I am not going to lie to you... This is part of a project I have to do for school. Although professionally I have worked with high level languages, my senior thesis professor threw us under the bus by forcing the entire class to code in C (which most of us have little to no experience with... :( ).

Either case, back to the problem. I have a global integer variable (starting from 0) which needs to be simultaneously incremented by 5 processes until it reaches 100 (100% rather).

Basically what's happening is that instead of individually modifying the completionCounter each child process is making a copy of it...

Is there a lock(object) or something of the sort as it is available in C#? I tried using a binary semaphore but I couldn't get it to work, i haven't played with shared memory yet.

const int THREADCOUNT = 5;
int completionCounter = 0;

int main(int argc, char **argv)
{
    int count = 0;
    pid_t pid;    

    for(count = 0; count<THREADCOUNT; count++)
    {
        if( (pid = fork()) < 0 )
        {
            //error...
            return -1;
        }
        else if( pid == 0 )
        {
            //child;
            while(completionCounter != 100 )
            {
                printf("[%i] process downloading data chunk...", getpid());

                //do stuff here

                completionCounter += 5;

            }
        }
        else
        {
            //parent.
        }
    }    
}
bleepzter
  • 9,607
  • 11
  • 41
  • 64
  • fork() creates a new process, not a thread - which is why they're creating a copy of the value. Edit: The way I would go about it would be to create a 'server' process, with 5 child 'worker' processes, which communicate with pipes http://www.gnu.org/s/libc/manual/html_node/Creating-a-Pipe.html – Rob Feb 21 '11 at 01:57
  • @Rob if i am to do it with forks, how would I force each child process to modify a global value rather than copy it? – bleepzter Feb 21 '11 at 02:02

3 Answers3

3

Child processes do not share variables with their parents. The only way you can do this with forked child processes is by specifically creating and mapping shared memory to hold the value.

A more reasonable way to do this would be to use threads rather than child processes, but it seems like you're stuck with the assignment you were given. In that case, I would recommend something like:

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

before forking, then incrementing *x in the child processes...

BUT!

Now you have to deal with synchronization. As-is, you'll easily get missing or duplicate numbers in your output. Lookup POSIX process-shared mutexes to get you started in that direction...

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • 1
    We don't actually know what assignment the OP was given. I don't see any reason to think that the professor required the project to use fork. – Jim Balter Feb 21 '11 at 02:18
  • @Jim: OP said "I have a global integer variable (starting from 0) which needs to be simultaneously incremented by 5 processes until it reaches 100". Threads are not processes. Of course it's possible that either OP or the instructor does not understand this... – R.. GitHub STOP HELPING ICE Feb 21 '11 at 02:21
  • The OP writes "This is part of a project I have to do for school." One cannot assume that the "problem" that the OP has was assigned by the professor -- this appears to be some subproblem that the OP has identified, but that could be based on an erroneous design. Note that the instructor is the OP's "senior thesis professor" -- that, and "project", suggest something considerably more advanced than the OP's problem statement. – Jim Balter Feb 21 '11 at 02:27
  • @Jim: OK I agree with your reasoning, and at the same time I think if it's right then OP's question is very poorly worded. – R.. GitHub STOP HELPING ICE Feb 21 '11 at 04:47
2

This is not being caused by a contention issue, it's the fact that when creating a new process (which is what happens when using fork), a new copy of the memory space is created. This means in effect that you are creating 5 completionCounters -- one for each process. Look into using pthreads if you want everything to share the same memory space.

user470379
  • 4,879
  • 16
  • 21
2

You are absolutely right, what you want can be achieved using semaphores. Try man 3 sem_wait, there's an example there.

vissi
  • 2,325
  • 1
  • 19
  • 26
  • Yes, however how do you get an instance of the semaphore? When you call `semget()` you only get an integer semaphore identifier. The reason why I couldn't do it with semaphores is that I couldn't get the semaphore value. Even the function that gets the value expects a `sem_t` object which I don't know how to obtain? – bleepzter Feb 21 '11 at 02:11
  • @bleepzter, Semaphore is used to protect access to some code in multi-thread environment. You can use shared memory to store your value and a semaphore (or pthreads mutex, if you are using threads) to protect it. – vissi Feb 21 '11 at 16:37