Reputation: 35
I'm trying to make a stack that I implemented thread safe using semaphors. It works when I push a single object onto the stack, but terminal freezes up as soon as I try to push a second item onto the stack or pop an item off of the stack. This is what I have so far and am not sure where I'm messing up. Everything complies right, but the terminal just freezes as previously stated
Heres where I create the stack
sem_t selements, sspace;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
BlockingStack *new_BlockingStack(int max_size)
{
sem_init(&selements, 0, 0);
sem_init(&sspace, 0, max_size);
BlockingStack *newBlockingStack = malloc(sizeof(BlockingStack));
newBlockingStack->maxSize = max_size;
newBlockingStack->stackTop = -1;
newBlockingStack->element = malloc(max_size * sizeof(void *));
if (newBlockingStack == NULL)
{
return NULL;
}
if (newBlockingStack->element == NULL)
{
free(newBlockingStack);
return NULL;
}
return newBlockingStack;
}
And here are the Push and Pop:
bool BlockingStack_push(BlockingStack *this, void *element)
{
sem_wait(&sspace);
pthread_mutex_lock(&m);
if (this->stackTop == this->maxSize - 1)
{
return false;
}
if (element == NULL)
{
return false;
}
this->element[++this->stackTop] = element;
return true;
pthread_mutex_unlock(&m);
sem_post(&selements);
}
void *BlockingStack_pop(BlockingStack *this)
{
sem_wait(&selements);
pthread_mutex_lock(&m);
if (this->stackTop == -1)
{
return NULL;
}
else
{
return this->element[this->stackTop--];
}
pthread_mutex_unlock(&m);
sem_post(&sspace);
}
Upvotes: 1
Views: 213
Reputation: 35
OK, i was working on this and finally cracked the answer after doing a little bit of internet research and debugging my code. The error was the the mutex_unlock and the sem_post had to come before the return.
Take my pop for example:
void *BlockingStack_pop(BlockingStack *this)
{
sem_wait(&selements);
pthread_mutex_lock(&m);
if (this->stackTop == -1)
{
return NULL;
}
else
{
return this->element[this->stackTop--];
}
pthread_mutex_unlock(&m);
sem_post(&sspace);
}
notice how the pthread_mutex_unlock(&m); and the sem_post(&sspace); come after the return, they actually must be placed before every return like so:
void *BlockingStack_pop(BlockingStack *this)
{
...
pthread_mutex_unlock(&m);
sem_post(&sspace);
return NULL;
...
pthread_mutex_unlock(&m);
sem_post(&sspace);
return this->element[this->stackTop--];
...
}
Upvotes: -1
Reputation: 154
For thread safety you already have mutex used (pthread_mutex_lock(&m) and pthread_mutex_unlock(&m)
). Using such mutual exclusion is enough for that purpose. Once one thread obtains the mutex, other thread blocks on pthread_mutex_lock(&m)
call.
And only the thread currently obtaining the mutex can call pthread_mutex_unlock(&m)
.
Upvotes: 1
Reputation: 121799
SUGGESTED CHANGES:
sem_t sem;
...
BlockingStack *new_BlockingStack(int max_size)
{
sem_init(&sem, 0, 1);
...
bool BlockingStack_push(BlockingStack *this, void *element)
{
sem_wait(&sem);
...
sem_post(&sem);
...
Specifically:
I would only initialize one semaphore object unless I was SURE I needed others
I would use the same semaphore for push() and pop()
pshared: 0
should be sufficent for synchronizing different pthreads inside your single process.
Initialize the semaphore to 1
, because the first thing you'll do for either "push" or "pop" is sem_wait()
.
Upvotes: 0