I'm trying to do some basic parallel processing to do an odd-even sort on integers using POSIX shared memory segments and unnamed semaphores. I have pretty much everything working at this point, except for one final thing: if I do not perror() directly after semaphore locks/unlocks the code acts differently (and subsequently sorts incorrectly). If I leave the perror() calls directly after semaphore locks and unlocks in, the code sorts the array of integers perfectly.
int semaphoreCheck = sem_init(&(sharedData->swapSem), 1, 1);
if (semaphoreCheck == -1)
{
p开发者_开发百科error( "failed to initialize semaphore" );
exit(EXIT_FAILURE);
}
pid_t fork1;
fork1 = fork();
if (fork1 == 0)
{
// original.child
pid_t fork2;
fork2 = fork();
if (fork2 == 0)
{
// child.child
// do a portion of the sort here
while(sharedData->evenSwap || sharedData->oddSwap)
{
// obtain lock on the shared vector
// int commandCheck = shmctl(sharedID, SHM_LOCK, NULL);
int commandCheck = sem_wait(&(sharedData->swapSem));
perror("semaphore lock");
// if lock was obtained
if (commandCheck == 0)
{
sharedData->evenSwap = false;
for( int index = 1; index < arraySize - 1; index +=2)
{
if( sharedData->vecData[index] > sharedData->vecData[index + 1] )
{
int temp;
temp = sharedData->vecData[index];
sharedData->vecData[index] = sharedData->vecData[index+1];
sharedData->vecData[index+1] = temp;
sharedData->evenSwap = true;
}
}
// release lock on the shared vector
commandCheck = sem_post(&(sharedData->swapSem));
perror("semaphore unlock");
if (commandCheck == -1)
{
perror("failed to unlock shared semaphore");
}
}
else perror("failed to lock shared semaphore");
}
_exit(0);
}
else if (fork2 > 0)
{
// child.parent
// do a portion of the sort here
while(sharedData->evenSwap || sharedData->oddSwap)
{
// obtain lock on the shared vector
int commandCheck = sem_wait(&(sharedData->swapSem));
perror("semaphore lock");
// if lock was obtained
if (commandCheck == 0)
{
sharedData->oddSwap = false;
for( int index = 0; index < arraySize - 1; index +=2)
{
if( sharedData->vecData[index] > sharedData->vecData[index + 1] )
{
int temp;
temp = sharedData->vecData[index];
sharedData->vecData[index] = sharedData->vecData[index+1];
sharedData->vecData[index+1] = temp;
sharedData->oddSwap = true;
}
}
// release lock on the shared vector
commandCheck = sem_post(&(sharedData->swapSem));
perror("semaphore unlock");
if (commandCheck == -1)
{
perror("failed to unlock shared semaphore");
}
}
else perror("failed to lock shared semaphore");
}
_exit(0);
}
else
{
// child.error
// forking error.
perror("failed to fork in child");
exit(EXIT_FAILURE);
}
}
else if( fork1 > 0)
{
// original.parent
// wait for the child process to finish.
waitpid(fork1, NULL, 0);
}
else
{
// forking error
perror("failed to fork");
exit(EXIT_FAILURE);
}
I can only guess that this has to do with how the semaphore blocks the process if a wait cannot be fulfilled, but I do not understand how perror() calls fix it.
I think your problem may be related to the way you are (not) checking that the conditions still apply after you get the semaphore, or that the checking conditions are themselves wrong.
You have:
while(sharedData->evenSwap || sharedData->oddSwap)
{
// obtain lock on the shared vector
int commandCheck = sem_wait(&(sharedData->swapSem));
perror("semaphore lock");
// if lock was obtained
if (commandCheck == 0)
{
sharedData->oddSwap = false;
After you get the semaphore, you should probably validate that either sharedData->evenSwap
or sharedData->oddSwap
is still true, relinquishing the semaphore if not. This is a standard idiom; you check, lock and recheck, because the status may have changed between the original check and the time you gain the lock.
Under this hypothesis, the perror()
calls alter the timing of the processes, allowing the conditions to stay unchanged for longer than when the perror()
calls are not present. So, there is a timing problem here, somewhere.
精彩评论