1

I have an array boxIn[] of type char that contains R R G B G B O Y O O P R characters. boxIn[] is in shared memory. There is also a char* in shared memory, p, that has a value of one of the chars in the boxIn[] array.

There are two semaphores defined in the program as follows:

/* initialize semaphores */
if((sem_init(&sem, pshared, value)) == 1){      /* only 2(value) processes at the same time */
    perror("Error initializing synch semaphore\n");
    exit(1);
}
if((sem_init(&mutex, pshared, 1)) == 1){        /* only 1 processes at the same time */
    perror("Error initializing synch semaphore\n");
    exit(1);
}

I fork the children from a for loop:

/* fork child processes */
for(i=0; i<n ; i++){
    pid = fork();
    if(pid < 0){    /* check for error  */
        printf("Fork error.\n");
    }
    else if(pid == 0) break;    /* child processes */

}

Then I let the children do some processing. At the moment I'm trying to get to my goal step by step. Therefore I change *p's value only once.

/******************************************************/
/******************   PARENT PROCESS   ****************/
/******************************************************/
if(pid != 0){
    while(wait()>0);
}

/******************************************************/
/******************   CHILD PROCESS   *****************/
/******************************************************/
else{
    while(*p != boxIn[i]); /* wait until it's my turn */
    sem_wait(&sem);
    printf("%c boxes are being painted.\n",boxIn[i]);
    printf("Done painting.\n");
    sleep(1);
    sem_wait(&mutex);
    if(*p=='R') *p='G';
    sem_post(&mutex);
    sem_post(&sem);
    exit(1);
}

However I do get an unexpected output:

What I expect is:

R boxes are being painted.
R boxes are being painted.
Done.
Done.
R boxes are being painted.
Done.
G boxes are being painted.
G boxes are being painted.
Done.
Done.

And what I get is as follows:

R boxes are being painted.
Done painting.
R boxes are being painted.
Done painting.
R boxes are being painted.
Done painting.
G boxes are being painted.
Done painting.
G boxes are being painted.
Done painting.
varaquilex@computer ~/Dropbox/Courses/BLG312E - Computer Operating Systems/hw3 $ G boxes are being painted.
Done painting.
G boxes are being painted.
Done painting.
G boxes are being painted.
Done painting.
G boxes are being painted.
Done painting.
G boxes are being painted.
G boxes are being painted.
Done painting.
Done painting.
G boxes are being painted.
Done painting.
G boxes are being painted.
Done painting.
P boxes are being painted.
Done painting.
P boxes are being painted.
Done painting.
P boxes are being painted.
Done painting.
P boxes are being painted.
Done painting.
P boxes are being painted.
Done painting.
^C

Question is: why do I get more than 2 G boxes painted even though there are only 2 G boxes in the boxIn[] array, and more importantly how do I even get P boxes painted, not to mention there is only one P box in the array and I get many P boxes painted?

Note: I have been trying for a long time. Not to mention that I used shift+C to stop many programs before this one. I restarted terminal and got this output. More interesting point is, I tried to print the value of i along with the box being painted and i saw that the output was mixed up! I mean, there were some rows that show G boxes(3) are being painted and some others were G boxes are being painted even though the printf() was printf("%c boxes(%d) are being painted",boxIn[i],i);. This is awkward, I restarted the operating system and got a different output from the same program. Can someone explain me why this occurs and how can I prevent this from occurring once again?

Varaquilex
  • 3,447
  • 7
  • 40
  • 60

1 Answers1

2

In order to use process-shared semaphores, they have to be in shared memory. Yours are not. So after the fork, each process has its own copy of the semaphore. The easiest way to allocate shared memory is:

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

However, despite being nearly universally available, anonymous mappings are not specified in POSIX, and thus, formally, "not portable". The alternative portable way to do this would be to make a temp file or POSIX shared memory object.

Or (here's the recommended way), use sem_open instead of sem_init.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • I thought the `pshared` parameter is used for sharing the semaphore between processes, as stated [here](http://man7.org/linux/man-pages/man3/sem_init.3.html). "The pshared argument indicates whether this semaphore is to be shared between the threads of a process, or between processes." If they are not used between processes, then what does this `pshared` argument mean? And also, my question was what is the meaning of this output? Why don't I get what I expect? – Varaquilex May 05 '13 at 21:12
  • Read the rest of the man page you linked to: "If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory (see shm_open(3), mmap(2), and shmget(2))." The following text about `fork` is misleading; it's only true if the mapping prior to the fork is shared. – R.. GitHub STOP HELPING ICE May 05 '13 at 21:18
  • 1
    As for why the `pshared` argument exists, it's purely an optimization. A non-shared semaphore can perform much better under contention than a shared one, but there's no way for `sem_init` to know whether you want the semaphore to be accessed by multiple processes unless you tell it, so the interface was designed such that you have to tell it. But in order for it to actually be usable in a process-shared way, it has to be located in shared memory. Otherwise there's no way for another process to act on it. – R.. GitHub STOP HELPING ICE May 05 '13 at 21:21
  • I tried to use `sem_open` as you suggested. Here is what I've tried: `sem = sem_open("/mysem", O_CREAT, 0644, 2);` ([from this answer](http://stackoverflow.com/a/8359403/2034041)). When the forked processes try to `sem_wait(sem)`, nothing happens. Can you help me further? And thank you very much for pointing out my crucial mistake. – Varaquilex May 05 '13 at 21:52
  • Before you go any further trouble, I want to declare that I have made them work:) thanks to [this answer](http://stackoverflow.com/a/6659866/2034041), I got it working now. However I need to know why linux, terminal, behaves this way. This is a messy situation and I need to know why in order to prevent it. +1 for your answer and explanatory comments btw. – Varaquilex May 05 '13 at 22:12