所以我正在考虑在 C++ 中使用简单的生产者/消费者队列。我最终将使用 boost 进行线程处理,但此示例仅使用 pthreads。我最终也会使用更多面向对象的方法,但我认为这会掩盖我目前感兴趣的细节。
无论如何,我担心的具体问题是
- 由于此代码使用 std::deque 的 push_back 和 pop_front - 它可能在不同线程中分配和释放底层数据 - 我认为这是不好的(未定义的行为) - 避免这种情况的最简单方法是什么?
- 没有任何东西被标记为易变的。但是重要的位是受互斥锁保护的。我是否需要将任何东西标记为 volatile 的,如果需要怎么办? - 我不认为我这样做是因为我相信互斥锁包含适当的内存屏障等,但我不确定。
还有其他明显的问题吗?
无论如何这是代码:
#include <pthread.h>
#include <deque>
#include <iostream>
struct Data
{
std::deque<int> * q;
pthread_mutex_t * mutex;
};
void* producer( void* arg )
{
std::deque<int> &q = *(static_cast<Data*>(arg)->q);
pthread_mutex_t * m = (static_cast<Data*>(arg)->mutex);
for(unsigned int i=0; i<100; ++i)
{
pthread_mutex_lock( m );
q.push_back( i );
std::cout<<"Producing "<<i<<std::endl;
pthread_mutex_unlock( m );
}
return NULL;
}
void* consumer( void * arg )
{
std::deque<int> &q = *(static_cast<Data*>(arg)->q);
pthread_mutex_t * m = (static_cast<Data*>(arg)->mutex);
for(unsigned int i=0; i<100; ++i)
{
pthread_mutex_lock( m );
int v = q.front();
q.pop_front();
std::cout<<"Consuming "<<v<<std::endl;
pthread_mutex_unlock( m );
}
return NULL;
}
int main()
{
Data d;
std::deque<int> q;
d.q = &q;
pthread_mutex_t mutex;
pthread_mutex_init( &mutex, NULL );
d.mutex = & mutex;
pthread_t producer_thread;
pthread_t consumer_thread;
pthread_create( &producer_thread, NULL, producer, &d );
pthread_create( &consumer_thread, NULL, consumer, &d );
pthread_join( producer_thread, NULL );
pthread_join( consumer_thread, NULL );
}
编辑:
我最终放弃了这个实现,我现在使用来自 here 的代码的修改版本安东尼·威廉姆斯。我的修改版本可以找到here此修改版本使用更明智的基于条件变量的方法。
最佳答案
Since this code is using push_back and pop_front of std::deque - it's probably doing allocation and deallocation of the underlying data in different threads - I believe this is bad (undefined behaviour) - what's the easiest way to avoid this?
只要一次只有一个线程可以修改容器,就可以了。
Nothing is marked volatile. But the important bits are mutex protected. Do I need to mark anything as volatile and if so what? - I don't think I do as I believe the mutex contains appropriate memory barriers etc., but I'm unsure.
只要您使用互斥锁正确地控制对容器的访问,它就不需要是volatile
(这取决于您的线程库,但它不会是一个很好的互斥锁如果它没有提供正确的内存屏障)。
关于c++ - 这个生产者/消费者的实现有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3278036/