user8666366
user8666366

Reputation:

Shared memory variable in c

I'm working on an assignment for uni and I'm having trouble defining the global variable Bank in shared memory so that my processes have a shared address. We are exploring race conditions and I'm supposed to have both processes call MakeTransactions() then make use of semaphores to eliminate the race condition. Currently, I keep running into an error of different type (int vs struct) regarding shared memory. Can someone explain what the best way to go about this is? Any suggestions would be helpful. Thanks!

    #include <unistd.h> 
    #include <stdio.h> 
    #include <stdlib.h>  
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/wait.h>

    struct Bank {
        int balance[2];
    };

    struct Bank = *bank;

    // routine for thread execution
    void* MakeTransactions() { 
        int i, j, tmp1, tmp2, rint;
        double dummy;

        for (i=0; i < 100; i++) {  
            rint = (rand()%30)-15; 
            if (((tmp1=bank->balance[0])+rint) >=0 &&
                    ((tmp2=bank->balance[1])-rint)>=0) { 
                bank->balance[0] = tmp1 + rint; 
                for (j=0; j < rint*100; j++) {
                    dummy=2.345*8.765/1.234; // spend time on purpose
                }
                bank->balance[1] = tmp2 - rint; 
            }  
        } 
        return NULL; 
    } 

    int main(int argc, char **argv) { 

        int i;
        void* voidptr = NULL;

            bank = mmap(NULL, sizeof(struct Bank), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
            //check if bank is not NULL
            bank->balance[0] = 100;
            bank->balance[1] = 100;

        pid_t pid;
        srand(getpid()); 

        printf("\nInit balances A:%d + B:%d ==> %d!", 
                bank->balance[0],bank->balance[1],bank->balance[0]+bank->balance[1]); 

        pid=fork();
        if (pid < 0) {
            fprintf(stderr, "Fork failed");
            return 1;
        }
        if (pid == 0) {
            printf("\nChild computing ...");
            MakeTransactions();
            printf("\nChild process complete");
            printf("\nLet's check the balances A:%d + B:%d ==> %d ?= 200",
            bank->balance[0],bank->balance[1],bank->balance[0]+bank->balance[1]);
            return 0;
        }
        else {
            printf("\nParent computing...\n");
            MakeTransactions();
            wait(NULL);
            printf("\nParent process complete\n");
            printf("Let's check the balances A:%d + B:%d ==> %d ?= 200\n\n",
                    bank->balance[0],bank->balance[1],bank->balance[0]+bank->balance[1]);
            return 0;
        }
        return 0; 
    }

Upvotes: 0

Views: 1648

Answers (1)

Jakub Piskorz
Jakub Piskorz

Reputation: 1073

I would start with a little refactoring of your code, so it would be clear why mmap in your comment cannot work.

Make your struct declaration non-annonymous:

struct Bank {
   int balance[2];
};

And your global: struct Bank bank = {{100,100}};. Now, this bank variable is on stack, which will make switch to mmap harder. Introduce indirection:

struct Bank bankGlobal = {{100, 100}};
struct Bank *bank = &bankGlobal;
...
bank->balance[0] = tmp1 + rint;

Now, bank is a pointer to struct Bank, and it currently points to bankGlobal. You need to change all bank. to bank->. With this code you can switch to mmap solution.

First, you cannot intialize your bank variable using mmap in global space. It has to be in function. Second, you are trying to obtain the size of a pointer to Bank (sizeof *Bank), when you should target entire struct size.

So, change this:

-struct Bank bankGlobal = {{100, 100}};
-struct Bank *bank = &bankGlobal;
+struct Bank *bank;

and in main function:

bank = mmap(NULL, sizeof(struct Bank), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
//check if bank is not NULL
bank->balance[0] = 100;
bank->balance[1] = 100;

Don't forget to munmap when you're done.

About races, you can put POSIX semaphore inside this Bank struct, and protect this transaction, with sem_wait and sem_post.

Upvotes: 1

Related Questions