【发布时间】:2011-03-17 17:19:51
【问题描述】:
所以我正在考虑在 C++ 中使用简单的生产者/消费者队列。我最终将使用 boost 进行线程处理,但这个示例只是使用 pthreads。我最终也会使用一种更加面向对象的方法,但我认为这会掩盖我目前感兴趣的细节。
无论如何,我担心的具体问题是
- 由于此代码使用 std::deque 的 push_back 和 pop_front - 它可能在不同线程中分配和释放底层数据 - 我认为这是不好的(未定义的行为) - 避免这种情况的最简单方法是什么?
- 没有任何东西被标记为易失性。但是重要的位是互斥保护的。我是否需要将任何内容标记为易失性,如果需要,怎么办? - 我不认为我这样做,因为我相信互斥体包含适当的内存屏障等,但我不确定。
还有其他明显的问题吗?
代码如下:
#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这个修改版使用了更明智的基于条件变量的方法。
【问题讨论】:
-
主要问题是您要求我们评估一个解决方案,您将撕毁并丢弃底层线程,然后还以“更多OO”的方式。我认为这被称为过早评估:-)
-
@paxdiablo:他的具体问题确实有其优点。但是对于幽默的术语 +1...
-
@paxdiablo 我只是想避免“使用对象”或“使用增强”形式的无用答案。我很清楚在迁移代码时可能会遇到其他问题 - 但我在此处获得的答案将在修改后的代码中保持相关性。
-
stackoverflow.com/questions/2363888 回答分配问题。摘要与 Amardeep 和 James McNellis 提到的内容相匹配……附带一个小条件,即由于标准未提及线程,行为是实现定义的(即未定义的行为),但所有/大多数当前实现实际上都将其定义为 OK - 这么久当您链接到正确的运行时库时。
-
我自己,我会说“此时使用对象或提升不是一个选项,所以请不要建议”。这有两件事:(1)让人们意识到你对那些答案不感兴趣; (2) 阻止被称为“pax”的令人讨厌的 yobbos 给您带来困难 :-) 感谢您的澄清。