如何使队列线程安全

时间:2018-03-07 08:04:43

标签: c multithreading thread-safety pthreads mutex

同时处理此队列的两个线程可能会使其失败。您将如何使并发访问正常工作?如果队列尝试从空队列中删除一个元素或者将一个元素添加到一个完整的队列中,那么队列是否应该让线程等待?

#include <stdlib.h>

// circular array
typedef struct _queue {
    int size;
    int used;
    int first;
    void **data;
} _queue;

#include "queue.h"

queue q_create(int size) {
    queue q = malloc(sizeof(_queue));

    q->size  = size;
    q->used  = 0;
    q->first = 0;
    q->data = malloc(size*sizeof(void *));

    return q;
}

int q_elements(queue q) {
    return q->used;
}

int q_insert(queue q, void *elem) {
    if(q->size==q->used) return 0;

    q->data[(q->first+q->used) % q->size] = elem;    
    q->used++;

    return 1;
}

void *q_remove(queue q) {
    void *res;
    if(q->used==0) return NULL;

    res=q->data[q->first];

    q->first=(q->first+1) % q->size;
    q->used--;

    return res;
}

void q_destroy(queue q) {
    free(q->data);
    free(q);
}

此队列的目标是管理我尝试开发的压缩工具的输入和输出。

1 个答案:

答案 0 :(得分:0)

线程安全意味着您必须隔离任何共享数据。这里您的共享数据是指向队列的指针。因此,通常,只要您对队列进行操作,就需要保护队列并防止多个线程到达您的队列同时排队。一个好方法是实现条件变量。变量是在关键数据中锁定线程的开关。

我在这里看不到线程代码。 所以,让我们假设你有一个写入队列的线程。 首先,您必须声明条件变量。

#include <pthread.h>


pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t w_condition = PTHREAD_COND_INITIALIZER;

que_state_t que_write_state = READY;  //this is just an enum


void* writer_thread_v2(void* t)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    int i = 0;
    while ( 1 )
    {
        pthread_mutex_lock(&mutex2);    
        while( que_write_state == NOT_READY )
        {
            pthread_cond_wait(&w_condition , &mutex2);
        }
        que_write_state = NOT_READY;
        person_t* doe = NULL;
        pthread_cleanup_push(clean_memory2, &doe);
        doe = (person_t*) malloc(sizeof(person_t));

        person_t static_person = random_person();
        doe->age_bracket = static_person.age_bracket;
        memcpy(doe->name , static_person.name , NAME_LENGTH);
        push(the_queue , doe );
        pthread_cleanup_pop(0);

        que_write_state = READY;
        pthread_mutex_unlock(&mutex2);
        pthread_cond_signal(&w_condition);
        i++;
    }
    pthread_exit(0);
}

此处线程进入while循环。

    pthread_mutex_lock(&mutex2);    //Here puts a lock on mutex    
    while( que_write_state == NOT_READY )    //Here checks the enum
    {
        pthread_cond_wait(&w_condition , &mutex2);
    }
    que_write_state = NOT_READY;      //Here puts the enum in not ready mode

现在所有此类线程都将停止并等待队列操作完成并释放互斥锁。 这里出现了一个很大的内存泄漏问题。如果一个线程创建了一个对象,并且在队列中添加数据之前它被取消了。这就是为什么在代码中有

pthread_cleanup_push(clean_memory2, &doe);
{
    inside here it mallocs the heap memory it is needed and adds data in 
    queue.If at any time the thread is cancelled clean_memory2() is called 
    which frees doe.
}
pthread_cleanup_pop(0);

pthread_cleanup_push将在创建您要存储的对象时保护您的内存泄漏,并完成导入过程。清理开关时,Clearup_push(ghost块)停止。 在推入que之后,该线程将释放互斥锁并向其余的线程发送信号。

    que_write_state = READY;   //here sets switch to ready mode
    pthread_mutex_unlock(&mutex2);   //unlocks mutex

    pthread_cond_signal(&w_condition); //signal the next one.

谢谢。