2014-02-13 3 views
1

Это правильный способ сделать Thread Safe Queue в C++, который может обрабатывать unsigned char * массивы двоичных данных?Thread Safe queue in C++

Обратите внимание, что данные генерируются из основного потока, а не из созданного pthread, что заставляет меня сомневаться в правильности работы pthread_mutex_t на push и pop.

Thread Safe Queue

#include <queue> 
#include <pthread.h> 

class ts_queue 
{ 

private: 

    std::queue<unsigned char*> _queue_; 
    pthread_mutex_t mutex; 
    pthread_cond_t cond; 

public: 

    ts_queue() 
    { 
     pthread_mutex_init(&mutex, NULL); 
     pthread_cond_init(&cond, NULL); 
    } 

    void push(unsigned char* data) 
    { 
     pthread_mutex_lock(&mutex); 

     _queue_.push(data); 

     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 

    void pop(unsigned char** popped_data) 
    { 
     pthread_mutex_lock(&mutex); 

     while (_queue_.empty() == true) 
     { 
      pthread_cond_wait(&cond, &mutex); 
     } 

     *popped_data = _queue_.front(); 
     _queue_.pop(); 

     pthread_mutex_unlock(&mutex); 
    } 
}; 

ПОТРЕБИТЕЛЬСКИХ ИСПЫТАНИЙ:

void *consumer_thread(void *arguments) 
{ 
    ts_queue *tsq = static_cast<ts_queue*>(arguments); 

    while (true) 
    { 
     unsigned char* data = NULL; 

     tsq->pop(&data); 

     if (data != NULL) 
     { 
      // Eureka! Received from the other thread!!! 
      // Delete it so memory keeps free. 
      // NOTE: In the real scenario for which I need 
      // this class, the data received are bitmap pixels 
      // and at this point it would be processed 
      delete[] data; 
     } 
    } 

    return 0; 
} 

ПРОИЗВОДИТЕЛЬ TEST:

void main() 
{ 
    ts_queue tsq; 

    // Create the consumer 
    pthread_t consumer; 
    pthread_create(&consumer, NULL, consumer_thread, &tsq)); 

    // Start producing 
    while(true) 
    { 
     // Push data. 
     // Expected behaviour: memory should never run out, as the 
     // consumer should receive the data and delete it. 
     // NOTE: test_data in the real purpose scenario for which I 
     // need this class would hold bitmap pixels, so it's meant to 
     // hold binary data and not a string 

     unsigned char* test_data = new unsigned char [8192]; 
     tsq.push(test_data); 
    } 

    return 0; 
} 

ответ

1

Как сделать йо Вы знаете, что потребитель никогда не получает данные? Когда я пытаюсь выполнить свою программу, у меня возникает ошибка сегментации, и GDB говорит мне, что потребитель получил указатель, но он недопустим.

Я считаю, что ваша проблема в том, что у вас есть гонка данных на члене _queue_. push() вызовов _queue_.push(data) (а запись на _queue_), удерживая push_mutex и pop() вызовов _queue_.front() (для чтения на _queue_) и _queue_.pop() (другая запись на _queue_), удерживая pop_mutex, но push() и pop() может происходить в то же время, в результате чего обе нити, чтобы быть запись (и чтение) _queue_ в то же время классическая гонка данных.