Search code examples
cposixshared-memory

C shared memory integer doesn't get updated


I'm implementing the reader-writers problem with C. As you can see I fork 2 times and each time will generate a reader or writer with some amount of waiting. I have also satisfied thread-safety using two semaphores. first the mutex which guards rcount, second the writeblock which guards mutual exclusion. The problem is that I the counter value doesn't change, despite the fact that I have used it as a shared memory.

The code:

#include <stdio.h>
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>





sem_t mutex,writeblock;
int data = 0,rcount = 0,shmid;


void reader()
{

 
  sem_wait(&mutex);
  rcount = rcount + 1;
  if(rcount==1)
   sem_wait(&writeblock);

  int *counter=shmat(shmid,NULL,0);
  printf("im a reader and counter is %d \n\n",*counter);
  shmdt(counter);
  sem_post(&mutex);

  sleep(1);
  sem_wait(&mutex);
  rcount = rcount - 1;
  if(rcount==0)
   sem_post(&writeblock);
  sem_post(&mutex);
}

void writer()
{


  sem_wait(&writeblock);

  int status=0;
  int *counter=shmat(shmid,NULL,0);
  *counter++;
  printf("im a writer and I incremented the counter and after that the counter is %d \n\n",*counter);
  shmdt(counter);

  sleep(1);
  sem_post(&writeblock);
}

int main()
{
    
  int i,b; 
  
  sem_init(&mutex,0,1);
  sem_init(&writeblock,0,1);
  
  shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
 
 if (shmid <0)
    printf("shmget err");
    



 if(fork()==0)
 {
    for (i=0;i<2;i++)
    {
        if(fork()==0)
        {
            sleep(i);
            writer();
            
            
        }
    }
 }

 else
 {
   for (i=0;i<2;i++)
    {
        if(fork()==0)
        {
            sleep(i*2);
            reader();
            
        }
    }
 }



}    

The error terminal:

$ im a reader and counter is 0 

im a writer and I incremented the counter and after that the counter is 0 

im a writer and I incremented the counter and after that the counter is 0 

im a reader and counter is 0 

im a writer and I incremented the counter and after that the counter is 0 

im a reader and counter is 0

Solution

  • As already stated in the other answer, the expression *counter++ is wrong. Due to the rules of operator precedence, it must be (*counter)++.

    However, even after fixing that error, your program will still not work as intended, for several reasons:

    In your question, you described the intended behavior of your program with the following statement:

    As you can see I fork 2 times and each time will generate a reader or writer with some amount of waiting.

    This statement of yours is incorrect. You actually fork 7 times, which means you have 8 processes. 3 of these processes will call the writer function and 3 will call the reader function.

    In the first for loop, the child process that is forked in the first iteration of the loop will call the writer function as intended, but afterwards, it will not break out of the loop. Instead, it will execute the second iteration of the loop. This means that you have two processes executing the second iteration of the loop.

    Since this probably is not intended, I suggest that you change the first for loop to the following:

    for (i=0;i<2;i++)
    {
        if(fork()==0)
        {
            sleep(i);
            writer();
            break; //breaks out of "for" loop
        }
    }
    

    Your second for loop (the one inside the else block) has the same issue.

    After fixing both loops, you will now only be forking 5 times, so that you have 6 processes in total. This is probably what you intended. The first process creates two writer processes and also creates a process which creates the two reader processes.

    However, another problem with your program is that every process has its own copy of the rcount variable. Therefore, you must do the same thing with that variable as you did with the counter variable (which is to use shared memory).

    Additonally, you are calling the function sem_init with the parameter pshared set to zero. According to the documentation of this function, this should only be done when the semaphore is shared between threads of the same process. However, with fork, you are creating separate processes. Therefore, you should set this parameter to nonzero.