Home > Software engineering >  How to let thread wait when I pop-empty-queue or push-full-queue
How to let thread wait when I pop-empty-queue or push-full-queue

Time:11-04

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.

  • Related