【问题标题】:How would the producer consumer problem be solve if there was 1 producer and many consumers Buffer size of 1如果有 1 个生产者和许多消费者缓冲区大小为 1,生产者消费者问题将如何解决
【发布时间】:2021-07-22 23:29:57
【问题描述】:

如果有 1 个提供文件名的生产者和两个消费文件名的消费者,生产者消费者问题将如何解决。

问题在于,添加文件名的缓冲区大小为 1,这意味着我们不能有 2 个副本供每个消费者使用。

两个消费者对同一个文件有不同的逻辑。

我没有包含退出条件逻辑,但它会在文件名等于 EXIT 时终止线程。

生产者/消费者之间通过指针共享数据。

共享数据:

    char* filenameBuffer;
    pthread_mutex_t filenameMutex;
    pthread_cond_t canProduceFilename;
    pthread_cond_t canConsumeFilename;

目前我让制片人做这样的事情。

父/生产者线程 - 将循环直到我想退出。

while(!exit)
{
    pthread_mutex_lock(filenameMutex);

    //Check if the string is empty.
    if(filenameBuffer != '\0')
    {
        p_thread_cond_wait(canProduceFilename, filenameMutex);
    }

    scanf("%s", filenameBuffer);

    pthread_cond_signal(canConsumeFilename);
    pthread_mutex_unlock(filenameMutex);
}

儿童/消费者线程 - 我们有 2 个。

while (!exit)
{
    pthread_mutex_lock(filenameMutex);

    //Loop until a string is produced.
    while (filenameBuffer == '\0')
    {
       p_thread_cond_wait(canConsumeFilename, filenameMutex);
    }

    //Do something with filename, not relevant for solution.

    pthread_mutex_unlock(filenameMutex);
}

那么我如何能够在不控制每个消费者线程的顺序的情况下使用消费者内部的文件名。我不想强制消费者可以先运行的顺序,因为这会破坏多线程的意义。

如果需要任何澄清或更多信息,我会留下来。

任何讨论或指导将不胜感激。

亲切的问候。

【问题讨论】:

  • 当你试图从两个线程同时读取一个文件时,你会遇到严重的问题。
  • 读取发生在文件名互斥体内部,因此一次只有一个消费者可以读取文件。
  • 我明白了。消费者只需使用一个作为文件名的字符串。字符串是文件名这一事实与问题无关,因为处理文件名不是问题的一部分。
  • 您希望两个线程同时处理两个文件,还是希望每个线程基本上随机处理文件名列表中的文件?
  • 如果您希望两个线程都处理所有文件名,则在互斥锁中实现一个计数器,以确保在读取下一个文件名之前读取每个文件名两次。

标签: c multithreading synchronization pthreads producer-consumer


【解决方案1】:

我编写了一个使用 Ada 编程语言如何工作的示例。由于文件名的处理对这个问题并不重要,我创建了两个消费者,它们处理他们收到的任何字符串,直到字符串等于“Exit”。

此示例创建一个包含单个元素缓冲区和计数器的受保护对象。它还实现了两个条目,写入和读取。写入口只在计数器等于0时执行。读入口只在计数器大于0时执行。

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

procedure Main is
   type Count_Type is range 0..2;
   protected buffer is
      entry write(S : in Unbounded_String);
      entry read(S : out Unbounded_String);
   private
      Counter : Count_Type := 0;
      Element : Unbounded_String;
   end Buffer;
   
   protected body buffer is
      entry write (S : in Unbounded_String) when Counter = 0 is
      begin
         Element := S;
         Counter := 2;
      end write;
      
      entry read (S : out Unbounded_String) when Counter > 0 is
      begin
         S := Element;
         Counter := Counter - 1;
      end read;
   end buffer;
   
   task producer;
   
   task body producer is
      Msg : Unbounded_String := To_Unbounded_String("Message");
   begin
      for I in 0..9 loop
         Msg := Msg & Integer'Image(I);
         Buffer.write(Msg);
      end loop;
      Msg := To_Unbounded_String("Exit");
      Buffer.Write(Msg);
   end producer;
   
   task consumer_1;
   
   task body consumer_1 is
      Msg : Unbounded_String;
   begin
      loop
         Buffer.Read(Msg);
         exit when To_String(Msg) = "Exit";
         Put_Line("Con1 -> " & To_String(Msg));
      end loop;
   end consumer_1;
   
   task consumer_2;
   
   task body consumer_2 is
      Msg : Unbounded_String;
   begin
      loop
         Buffer.Read(Msg);
         exit when To_String(Msg) = "Exit";
         Put_Line("Con2 -> " & To_String(Msg));
      end loop;
   end consumer_2;
begin
   null;
end Main;

程序的输出是:

Con1 -> Message 0
Con2 -> Message 0
Con1 -> Message 0 1
Con2 -> Message 0 1
Con1 -> Message 0 1 2
Con2 -> Message 0 1 2
Con2 -> Message 0 1 2 3
Con2 -> Message 0 1 2 3 4
Con1 -> Message 0 1 2 3
Con2 -> Message 0 1 2 3 4
Con1 -> Message 0 1 2 3 4 5
Con2 -> Message 0 1 2 3 4 5
Con1 -> Message 0 1 2 3 4 5 6
Con2 -> Message 0 1 2 3 4 5 6
Con1 -> Message 0 1 2 3 4 5 6 7
Con2 -> Message 0 1 2 3 4 5 6 7
Con1 -> Message 0 1 2 3 4 5 6 7 8
Con2 -> Message 0 1 2 3 4 5 6 7 8
Con1 -> Message 0 1 2 3 4 5 6 7 8 9
Con2 -> Message 0 1 2 3 4 5 6 7 8 9

【讨论】:

    猜你喜欢
    • 2011-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多