这个生产者/消费者实施的问题是什么? [英] What are the problems with this producer/consumer implementation?

查看:135
本文介绍了这个生产者/消费者实施的问题是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在C ++中使用一个简单的生产者/消费者队列。我将最终使用boost的线程,但这个例子只是使用pthreads。我也会使用更多的OO方法,但我认为这会模糊我目前感兴趣的细节。



无论如何,具体问题


  1. 由于此代码使用的是push_back和pop_front的std :: deque - 它可能正在进行底层的分配和重新分配数据在不同的线程 - 我相信这是坏的(未定义的行为) - 什么是最简单的方法来避免这个?

  2. 没有标记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()
{
数据d;

std :: deque< int> q;
d.q =& q;

pthread_mutex_t mutex;
pthread_mutex_init(& mutex,NULL);
d.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);
}

EDIT: b

我最终抛弃了这个实现,我现在使用的修改版本的代码这里。我的修改版本可以在此处找到。此修改版本使用了一种更加合理的基于条件变量的方法。

解决方案


  1. 在一个线程中分配内存并在另一个线程中释放内存是完全有效的


  2. 使用互斥保护访问deque应提供正确的内存访问配置。


EDIT:唯一需要考虑的是生产者和消费者的本质。您的合成示例缺少一些与实际实现相关的微妙之处。例如,如果生产者与消费者不以完全相同的速率运行,您将如何将其同步?您可能需要考虑使用管道或操作系统队列而不是deque,以便如果没有数据准备处理,消费者可以在读取时阻塞。


So I'm looking at using a simple producer/consumer queue in C++. I'll end up using boost for threading but this example is just using pthreads. I'll also end up using a far more OO approach, but I think that would obscure the details I'm interested in at the moment.

Anyway the particular issues I'm worried about are

  1. 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?
  2. 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.

Are there any other glaring issues?

Anyway heres the code:

#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 );
}

EDIT:

I did end up throwing away this implementation, I'm now using a modified version of the code from here by Anthony Williams. My modified version can be found here This modified version uses a more sensible condition variable based approach.

解决方案

  1. It is perfectly valid to allocate memory in one thread and free it in another if both threads are in the same process.

  2. Using a mutex to protect access to the deque should provide the correct memory access configuration.

EDIT: The only other thing to think about is the nature of the producer and consumer. Your synthesized example lacks some of the subtleties involved with a real implementation. For example, how will you synchronize the producer with the consumer if they are not operating at the exact same rate? You might want to consider using something like a pipe or an OS queue instead of a deque so that the consumer can block on read if there is no data ready to process.

这篇关于这个生产者/消费者实施的问题是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆