Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++多线程生产者-消费者问题_C++_Multithreading_Producer Consumer - Fatal编程技术网

C++多线程生产者-消费者问题

C++多线程生产者-消费者问题,c++,multithreading,producer-consumer,C++,Multithreading,Producer Consumer,我用条件变量编写了一个乘法生产者和消费者的代码。 即使我只有一个生产者和一个消费者,它也不起作用。 生产者和消费者都应该在真实的环境中运行。 当我运行代码时,大约50%的运行被卡住了。 我想它会因为等待过度而陷入僵局。 我没有成功地调试它被阻塞的地方以及如何解锁条件。 根据请求,我必须创建带有等待、信号和广播的代码 如果队列已满,则生产者正在等待。 如果队列为空,则消费者正在等待 void WaitableQueue::enqueue(size_t a_item) { (m_cond.g

我用条件变量编写了一个乘法生产者和消费者的代码。 即使我只有一个生产者和一个消费者,它也不起作用。 生产者和消费者都应该在真实的环境中运行。 当我运行代码时,大约50%的运行被卡住了。 我想它会因为等待过度而陷入僵局。 我没有成功地调试它被阻塞的地方以及如何解锁条件。 根据请求,我必须创建带有等待、信号和广播的代码

如果队列已满,则生产者正在等待。 如果队列为空,则消费者正在等待

void WaitableQueue::enqueue(size_t a_item)
{
    (m_cond.getMutex()).lock();

    while(m_itemsCounter==m_capacity && !m_isBeingDestroyed)
    {
        ++m_numberOfWaiting;
        m_cond.wait();
        --m_numberOfWaiting;
    }

    std::cout<<"enqueue "<<a_item<<"\n";

    m_queue.push(a_item);
    ++m_itemsCounter;
    ++m_numbOfProduced;
    if(m_isBeingDestroyed)
    {
        m_cond.broadcast(); 
    }

    (m_cond.getMutex()).unlock();
    m_cond.broadcast();
}

void WaitableQueue::dequeue()
{
    (m_cond.getMutex()).lock();

    while(m_itemsCounter==0 && !m_isBeingDestroyed)
    {
        ++m_numberOfWaiting;
        std::cout<<"Waiting\n";
        m_cond.wait();
        std::cout<<"Done waiting\n";
        --m_numberOfWaiting;
    }

    if (m_isBeingDestroyed)
    {
        (m_cond.getMutex()).unlock();
        m_cond.broadcast();
        return;
    }
    std::cout<<"dequeue "<<m_queue.front()<<"\n";
    m_queue.pop();
    --m_itemsCounter;
    ++m_numbOfConsumed;
    (m_cond.getMutex()).unlock();
    m_cond.broadcast();
}

void WaitableQueue::destroy()
{
    (m_cond.getMutex()).lock();
    m_isBeingDestroyed=true;
    (m_cond.getMutex()).unlock();
}



void Producer::run()
{
    for(size_t i=0;i<m_numOfItemsToProduce;++i)
    {
        usleep(m_delay);
        size_t item=produce();
        m_wq.enqueue(item);
    }
}


Producer::produce() const
{
    return rand()%m_numOfItemsToProduce;
}

void Consumer::run()
{
    m_numOfProducersMutex.lock();
    while(m_numOfProducers>0)
    {
        m_numOfProducersMutex.unlock();
        usleep(m_delay);
        m_wq.dequeue();
        m_numOfProducersMutex.lock();
    }
    m_numOfProducersMutex.unlock();
}


int main()
{
    size_t numProducers=1;
    size_t numConsumers=3;
    Mutex mutex;
    ConditionalVariable cond(mutex);

    WaitableQueue<size_t> wq(NUM_OF_ITEMS,cond);
    std::vector<Producer<size_t>*> producerArray;
    std::vector<Consumer<size_t>*> consumerArray;
    Mutex numOfProducersMutex;

    for(size_t i=0;i<numProducers;++i)
    {
        Producer<size_t>* tempP=new Producer<size_t>(wq,NUM_OF_ITEMS,DELAY);
        producerArray.push_back(tempP);
    }

    for(size_t i=0;i<numConsumers;++i)
    {
        Consumer<size_t>* tempC=new Consumer<size_t>(wq,numProducers,numOfProducersMutex,DELAY);
        consumerArray.push_back(tempC);
    }

    for(size_t i=0;i<numProducers;++i)
    {
        producerArray[i]->start();
    }

    for(size_t i=0;i<numConsumers;++i)
    {
        consumerArray[i]->start();
    }

    for(size_t i=0;i<numProducers;++i)
    {
        producerArray[i]->join();
        numOfProducersMutex.lock();
        --numProducers;
        numOfProducersMutex.unlock();
    }
    usleep(100);

    //tell the consumers stop waiting
    wq.destroy();
   for(size_t i=0;i<numConsumers;++i)
    {
        consumerArray[i]->join();
    }

   for(size_t i=0;i<numProducers;++i)
   {
        delete producerArray[i];
   }

    for(size_t i=0;i<numConsumers;++i)
   {
        delete consumerArray[i];
   }
}
它在大约50%的跑步中有效。
在其他50%中,它被剔除了。

< p>你发现了C++如何从概念上简单的问题中解决一个难题的另一个例子。 似乎您希望一个或多个生产者生成相同数量的值,并让一组消费者读取和处理这些值。您似乎还希望生产者的数量等于消费者的数量,同时允许生产者和消费者的数量可以配置

这个问题使用Ada非常简单,Ada的设计考虑了并发性

第一个文件是定义生产者和消费者任务类型的Ada包规范

generic
   Items_To_Handle : Positive;
package Integer_Prod_Con is

   task type Producer;

   task type Consumer;

end Integer_Prod_Con;
泛型参数非常类似于模板参数。在这种情况下,作为泛型参数传递的值必须是正整数。 该方案的实施如下

with Ada.Containers.Synchronized_Queue_Interfaces;
with Ada.Containers.Unbounded_Synchronized_Queues;
with Ada.Text_Io; use Ada.Text_IO;

package body Integer_Prod_Con is
   package Int_Interface is new Ada.Containers.Synchronized_Queue_Interfaces(Integer);
   package Int_Queue is new Ada.Containers.Unbounded_Synchronized_Queues(Queue_Interfaces =>Int_Interface);
   use Int_Queue;

   The_Queue : Queue;

   --------------
   -- Producer --
   --------------

   task body Producer is
   begin
      for Num in 1..Items_To_Handle loop
         The_Queue.Enqueue(Num);
         delay 0.010;
      end loop;
   end Producer;

   --------------
   -- Consumer --
   --------------

   task body Consumer is
      Value : Integer;
   begin
      for Num in 1..Items_To_Handle loop
         The_Queue.Dequeue(Value);
         Put_Line(Value'Image);
         delay 0.010;
      end loop;
   end Consumer;

end Integer_Prod_Con;
该包使用预定义的通用包实现一个无界队列作为缓冲区。这允许队列根据程序的需要增长和收缩。每个生产者任务将从1到项目_到_Handle的整数值排成队列,每个消费者排成队列并从队列中输出相同数量的元素

该计划的主要程序是:

with Integer_Prod_Con;

procedure Int_Queue_Main is
   PC_Count : constant := 3;

   package short_list is new Integer_Prod_Con(10);
   use short_List;

   Producers : Array(1..PC_Count) of Producer;
   Consumers : Array(1..PC_Count) of Consumer;
begin
   null;
end Int_Queue_Main;
 1
 1
 1
 2
 2
 2
 3
 3
 3
 4
 4
 4
 5
 5
 5
 6
 6
 6
 7
 7
 7
 8
 8
 8
 9
 9
 9
 10
 10
 10
该程序的输出为:

with Integer_Prod_Con;

procedure Int_Queue_Main is
   PC_Count : constant := 3;

   package short_list is new Integer_Prod_Con(10);
   use short_List;

   Producers : Array(1..PC_Count) of Producer;
   Consumers : Array(1..PC_Count) of Consumer;
begin
   null;
end Int_Queue_Main;
 1
 1
 1
 2
 2
 2
 3
 3
 3
 4
 4
 4
 5
 5
 5
 6
 6
 6
 7
 7
 7
 8
 8
 8
 9
 9
 9
 10
 10
 10

你发现了C++如何从概念上简单的问题中解决难题的另一个例子。

似乎您希望一个或多个生产者生成相同数量的值,并让一组消费者读取和处理这些值。您似乎还希望生产者的数量等于消费者的数量,同时允许生产者和消费者的数量可以配置

这个问题使用Ada非常简单,Ada的设计考虑了并发性

第一个文件是定义生产者和消费者任务类型的Ada包规范

generic
   Items_To_Handle : Positive;
package Integer_Prod_Con is

   task type Producer;

   task type Consumer;

end Integer_Prod_Con;
泛型参数非常类似于模板参数。在这种情况下,作为泛型参数传递的值必须是正整数。 该方案的实施如下

with Ada.Containers.Synchronized_Queue_Interfaces;
with Ada.Containers.Unbounded_Synchronized_Queues;
with Ada.Text_Io; use Ada.Text_IO;

package body Integer_Prod_Con is
   package Int_Interface is new Ada.Containers.Synchronized_Queue_Interfaces(Integer);
   package Int_Queue is new Ada.Containers.Unbounded_Synchronized_Queues(Queue_Interfaces =>Int_Interface);
   use Int_Queue;

   The_Queue : Queue;

   --------------
   -- Producer --
   --------------

   task body Producer is
   begin
      for Num in 1..Items_To_Handle loop
         The_Queue.Enqueue(Num);
         delay 0.010;
      end loop;
   end Producer;

   --------------
   -- Consumer --
   --------------

   task body Consumer is
      Value : Integer;
   begin
      for Num in 1..Items_To_Handle loop
         The_Queue.Dequeue(Value);
         Put_Line(Value'Image);
         delay 0.010;
      end loop;
   end Consumer;

end Integer_Prod_Con;
该包使用预定义的通用包实现一个无界队列作为缓冲区。这允许队列根据程序的需要增长和收缩。每个生产者任务将从1到项目_到_Handle的整数值排成队列,每个消费者排成队列并从队列中输出相同数量的元素

该计划的主要程序是:

with Integer_Prod_Con;

procedure Int_Queue_Main is
   PC_Count : constant := 3;

   package short_list is new Integer_Prod_Con(10);
   use short_List;

   Producers : Array(1..PC_Count) of Producer;
   Consumers : Array(1..PC_Count) of Consumer;
begin
   null;
end Int_Queue_Main;
 1
 1
 1
 2
 2
 2
 3
 3
 3
 4
 4
 4
 5
 5
 5
 6
 6
 6
 7
 7
 7
 8
 8
 8
 9
 9
 9
 10
 10
 10
该程序的输出为:

with Integer_Prod_Con;

procedure Int_Queue_Main is
   PC_Count : constant := 3;

   package short_list is new Integer_Prod_Con(10);
   use short_List;

   Producers : Array(1..PC_Count) of Producer;
   Consumers : Array(1..PC_Count) of Consumer;
begin
   null;
end Int_Queue_Main;
 1
 1
 1
 2
 2
 2
 3
 3
 3
 4
 4
 4
 5
 5
 5
 6
 6
 6
 7
 7
 7
 8
 8
 8
 9
 9
 9
 10
 10
 10

要使用条件变量解决生产者-消费者问题,首先需要了解有界缓冲区问题

检查C++中使用条件变量实现线程安全缓冲队列:

您可以使用此缓冲区队列作为构建块来解决多产品消费者问题。 请在此检查如何使用线程安全缓冲区队列来解决C++中的生产者-消费者问题:
要使用条件变量解决生产者-消费者问题,首先需要了解有界缓冲区问题

检查C++中使用条件变量实现线程安全缓冲队列:

您可以使用此缓冲区队列作为构建块来解决多产品消费者问题。 请在此检查如何使用线程安全缓冲区队列来解决C++中的生产者-消费者问题:

建议您不要自己锁定和解锁互斥锁,这可能不会解决您当前的问题,但可能会解决未来的问题。请确保使用帮助程序解锁互斥体,例如仔细查看代码,我认为您应该查看显示更好的使用条件变量的方法。在等待空/满队列时锁定互斥体后,您不会解锁互斥体。您需要在等待之前释放互斥锁。如果调试代码,您会发现一个线程在锁定互斥锁时正在等待CV,而另一个线程则在等待获取互斥锁。在调用CV.wait之前解锁互斥锁。这可能有一些竞争条件,所以要小心。@实际上,在调用CV wait之前,应该始终锁定互斥锁。在本例中,看起来CV周围有一个自定义类包装器,它将互斥体与CV关联起来。只要您始终使用该锁保护CV循环等待条件,就可以了,这里就是这种情况,请提供剩余的cod

E请注意,如果在调试器处于死锁状态时暂停调试器,它将显示死锁的位置。建议您不要自己锁定和解锁互斥锁,这可能不会解决当前的问题,但可能会解决未来的问题。请确保使用帮助程序解锁互斥体,例如仔细查看代码,我认为您应该查看显示更好的使用条件变量的方法。在等待空/满队列时锁定互斥体后,您不会解锁互斥体。您需要在等待之前释放互斥锁。如果调试代码,您会发现一个线程在锁定互斥锁时正在等待CV,而另一个线程则在等待获取互斥锁。在调用CV.wait之前解锁互斥锁。这可能有一些竞争条件,所以要小心。@实际上,在调用CV wait之前,应该始终锁定互斥锁。在本例中,看起来CV周围有一个自定义类包装器,它将互斥体与CV关联起来。只要您始终使用该锁保护CV循环等待条件,这是很好的,这里就是这种情况,请提供代码的其余部分。注意,如果在死锁时暂停调试器,它将显示死锁在哪里。问题是用C++标记的,我相信OP需要C++应答。另外,这不是C++如何解决一个难题的另一个例子。并发需要理解,如果您理解它,那么C++实现是简单的。@每个人-问题也被标记在生产者消费者中,并被回答为生产者消费者问题的正确实施的例子。是的,并发需要理解,C++线程库不便于理解。在生产者和消费者中放置锁定/解锁对有故障。它们属于共享缓冲区的类方法,因为它们是缓冲区的行为。将锁定调用放在缓冲区方法之外显然违反了缓冲区的封装和内聚。回答这个问题是不可接受的,只需在其他编程语言中进行即可。问题是标题和标记C++。用户通常不可能选择语言。每种语言都有不同的多线程语义,所以从另一种语言中得到的例子是没有帮助的。请给出一个理由,说明C++从概念上简单的问题中提出了一个难题。你是说C++不能优雅地完成PRODCONS吗?尽管C++具有较少的内置抽象,但这是因为它不太喜欢猜测用户如何定制性能。需要考虑如何定制性能本身就是过早优化的一个症状。这并不意味着提供定制性能的能力是错误的。这确实意味着应该有一个不需要过早优化的默认性能级别,就像其他语言构造(如循环)一样。为了提高性能,通常使用循环而不是手动展开循环。不是提供一个低级别并发控制的选项,C++强制所有并发到一个低级别的控制,这很少是优雅的。问题是C++中的标记,我相信OP需要C++的答案。另外,这不是C++如何解决一个难题的另一个例子。并发需要理解,如果您理解它,那么C++实现是简单的。@每个人-问题也被标记在生产者消费者中,并被回答为生产者消费者问题的正确实施的例子。是的,并发需要理解,C++线程库不便于理解。在生产者和消费者中放置锁定/解锁对有故障。它们属于共享缓冲区的类方法,因为它们是缓冲区的行为。将锁定调用放在缓冲区方法之外显然违反了缓冲区的封装和内聚。回答这个问题是不可接受的,只需在其他编程语言中进行即可。问题是标题和标记C++。用户通常不可能选择语言。每种语言都有不同的多线程语义,所以从另一种语言中得到的例子是没有帮助的。请给出一个理由,说明C++从概念上简单的问题中提出了一个难题。你是说C++不能优雅地完成PRODCONS吗?尽管C++具有较少的内置抽象,但这是因为它不太喜欢猜测用户如何定制性能。需要考虑如何定制性能本身就是过早优化的一个症状。这并不意味着提供定制性能的能力是错误的。这确实意味着应该有一个不需要过早优化的默认性能级别,就像其他语言构造(如循环)一样。为了提高性能,通常使用循环而不是手动展开循环。而不是 提供并发控制C++的低级别控制的选项迫使所有并发到低级别的控制,这很少是优雅的。