所以我正在考虑在C ++中使用一个简单的生产者/消费者队列。我最终会使用boost进行线程化,但这个例子只是使用pthreads。我最终还会使用更多的OO方法,但我认为这会掩盖我目前感兴趣的细节。
无论如何,我担心的特殊问题是
还有其他明显的问题吗?
无论如何都是代码:
#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 );
}
修改
我最终放弃了这个实现,我现在正在使用Anthony Williams的here代码的修改版本。可以找到我的修改版本here此修改版本使用更合理的基于条件变量的方法。
答案 0 :(得分:2)
由于此代码使用的是st_ :: deque的push_back和pop_front - 它可能在不同的线程中对底层数据进行分配和释放 - 我认为这很糟糕(未定义的行为) - 避免这种情况最简单的方法是什么? / p>
只要一个线程一次只能修改容器,这没关系。
没有任何东西标记为不稳定。但重要的部分是互斥保护。我是否需要将任何东西标记为易变的,如果是这样的话? - 我不认为我这样做,因为我认为互斥锁包含适当的内存屏障等,但我不确定。
只要您使用互斥锁正确控制对容器的访问,它就不需要volatile
(这取决于您的线程库,但如果它没有,它将不是一个非常好的互斥锁不提供正确的记忆障碍。
答案 1 :(得分:1)
如果两个线程都在同一个进程中,那么在一个线程中分配内存并在另一个线程中释放它是完全有效的。
使用互斥锁保护对双端队列的访问应提供正确的内存访问配置。
编辑:唯一需要考虑的是生产者和消费者的性质。您合成的示例缺少真正实现所涉及的一些细微之处。例如,如果生产者没有以完全相同的速率运营,您将如何将生产者与消费者同步?您可能需要考虑使用管道或OS队列而不是双端队列,以便在没有数据准备好处理时,消费者可以阻止读取。