Is this the correct way to make a Thread Safe Queue in C++ which can handle unsigned char* arrays of binary data?
Notice that in the data is produced from the main thread and not a created pthread, which makes me question if the pthread_mutex_t will actually work correctly on the push and 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);
}
};
CONSUMER TEST:
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;
}
PRODUCER 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;
}
How do you know the consumer never gets the data? When I try your program out, I get a segmentation fault, and GDB tells me the consumer did get a pointer, but it's an invalid one.
I believe your problem is that you have a data race on the _queue_
member. push()
calls _queue_.push(data)
(a write on _queue_
) while holding push_mutex
and pop()
calls _queue_.front()
(a read on _queue_
) and _queue_.pop()
(another write on _queue_
) while holding pop_mutex
, but push()
and pop()
can occur at the same time, causing both threads to be writing (and reading) _queue_
at the same time, a classical data-race.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.