I am currently working on a queue structure which is tread-safe. I lock before editing queue in push and pop. Unlock it when I finish doing that. Now I want to let thread wait when pop-empty-queue or push-full-queue(this queue is sized). So I check if queue is full at the beginning of push, and use same way to check if queue is empty the beginning of pop. If it is then I let it wait by pthread_cond_wait
. To let it stop waiting, I check if queue is still empty at the end of push, and check if queue is still full at the end of pop. Is it's not empty or full, then I use pthread_cond_signal
to wake up the thread. The struct that I defined is like
typedef struct node_t {
void* content;
struct node_t *next;
struct node_t *prev;
} node_t;
typedef struct queue_t {
node_t* head;
node_t* tail;
int size;
int count;
pthread_mutex_t mutex;
pthread_cond_t full; // To deal with the condition that the queue is full
pthread_cond_t empty; // To deal with the condition that the queue is empty
} queue_t;
And the way I use lock and wait & send code is like:
bool queue_push(queue_t *q, void *elem) {
if (q == NULL) {
return false;
}
while (q->count == q->size) {
pthread_cond_wait(&q->full, &q->mutex);
}
if (q->head == NULL) {
pthread_mutex_lock(&q->mutex);
// I skip the steps for adding a node to queue
if (q->count != 0) {
pthread_cond_signal(&q->empty);
}
pthread_mutex_unlock(&q->mutex);
return true;
} else {
pthread_mutex_lock(&q->mutex);
// I skip the steps for adding a node to queue
if (q->count != 0) {
pthread_cond_signal(&q->empty);
}
pthread_mutex_unlock(&q->mutex);
return true;
}
}
And the code for pop is kind of similar.
bool queue_pop(queue_t *q, void **elem) {
if (q->count == 0) {
pthread_cond_wait(&q->empty, &q->mutex);
}
if (q->head == q->tail) {
pthread_mutex_lock(&q->mutex);
// I skip the steps for deleting a node to queue
if (q->count != q->size) {
pthread_cond_signal(&q->full);
}
pthread_mutex_unlock(&q->mutex);
return true;
} else {
pthread_mutex_lock(&q->mutex);
// I skip the steps for deleting a node to queue
if (q->count != q->size) {
pthread_cond_signal(&q->full);
}
pthread_mutex_unlock(&q->mutex);
return true;
}
}
Now when I use my test cases to test it, it never end. But I did unlock and send signal to let thread stop waiting. Can someone help me about this? Thanks!
CodePudding user response:
If you are using c just use semaphore or if you are using c you can use POSIX semaphore, if you want to implement it yourself check spinlock. In any case you can implement blocker and releaser with spinlock,you can create a middleware(chain responsibility pattern) and use it on all calls. Something like this.
void middleware (int (*func)(int, int)) {
block();
then();
release();
}
In case of c you can use templates to achieve one middleware for all methods.