Reputation: 3463
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 char
s 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?
Upvotes: 1
Views: 712
Reputation: 215287
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
.
Upvotes: 2