【问题标题】:Multithreading using pthread in C++ with shared variables在 C++ 中使用带有共享变量的 pthread 进行多线程
【发布时间】:2012-10-06 15:19:20
【问题描述】:

我不熟悉线程(以及 C/C++),我正在尝试使用多个线程来访问共享变量。

我主要创建了一个变量 char inputarray[100];

线程 1:该线程将以 2 字节突发从标准输入读取数据,并将它们附加到输入数组。 (通过输入文件输入)

线程 2:该线程将一次读取 1 个字节的数据,执行计算,并将其数据放入输出数组。

线程 3:该线程将以 2 字节突发的形式从输出数组中输出数据。 (标准输出)

我尝试了输入部分并通过传递结构使其工作,但想在不使用结构的情况下进行,但它给我带来了问题。

如果我能将输入记录下来,我相信我将能够使用类似的策略来完成输出。任何帮助将不胜感激。

下面是输入线程的粗略模板。

#include <stdio.h>
#include <pthread.h>

using namespace std;

void* input(void* arg) {
    char reading[3];
    fread(reading,1,2,stdin);

    //append to char inputarray[]..???
}

int main() {
    char inputarray[100];
    pthread_t t1;
    pthread_create(&t1, NULL, &input, &inputarray);
    void *result;
    pthread_join(t1,&result);
    return 0;
}  

【问题讨论】:

    标签: c++ multithreading pthreads parameter-passing


    【解决方案1】:

    几个问题:

    1. 我认为堆栈上的数组对于共享变量来说是非常糟糕的选择,因为它具有固定的大小,并且从线程 2 和 3 中不清楚将新元素放在哪里或从哪里读取元素。我建议改用std::vectorstd::deque。 最初,您的容器是空的。然后线程 2 将一些元素推送给它。 线程 3 正在轮询(或等待条件变量)容器,一旦找到新元素 - 打印它们

    2. 您必须使用互斥锁同步对共享变量的访问(考虑 pthread 互斥锁,std::mutexboost::mutex)。您可能还想使用条件变量来通知线程 3 队列中的新元素。但对于初始实施,它是不需要的。

    3. 您真的必须使用 pthread 原语吗?通常使用std::threadstd::mutex(如果您有现代编译器)或boost::threadboost::mutex 否则会更容易和更安全(即异常安全)。

    【讨论】:

      【解决方案2】:

      你在正确的轨道上:

      请注意,pthreads 库是 C 库,因此您需要将回调声明为 C 函数:

      extern "C" void* input(void* arg);
      

      我个人会传递第一个元素的地址:

      pthread_create(&t1, NULL, &input, &inputarray[0]);
      

      这会让你的代码看起来像这样:

      void* input(void* arg) {
      
          try
          {
             char*  inputarray    = (char*)arg;
             size_t inputLocation = 0;
      
             // Need to make sure you don't over run the buffer etc...
             while(!finished())
             {
                fread(&inputarray[inputLocation],1,2,stdin);
                inputLocation += 2;
             }
          }
          catch(...){} // Must not let exceptions escape a thread.
          return NULL;
      }
      

      这种风格的问题在于您将协调的责任放到了每个单独的线程中。写入线程必须检查是否结束,读取线程必须检查是否有可用数据等。所有这些都需要协调,所以现在您需要一些共享互斥锁和条件变量。

      更好的选择是将责任转移到进行通信的对象中。因此,我将创建一个具有通信所需基本操作的类,然后对其方法进行适当的检查。

       class Buffer
       {
           public:
              void write(......); //
              void read(.....);   //
           private:
              // All the synchronization and make sure the two threads
              // behave nicely inside the object.
       };
      
       int main()
       {
             pthread_t threads[3];
             std::pair<Buffer, Buffer>   comms;
             // comms.first     inputToRead
             // comms.second    processesToOutput
      
      
             pthread_create(&threads[0], NULL, &readInput, &comms.first);   // Input
             pthread_create(&threads[1], NULL, &procInput, &comms);         // Processing
             pthread_create(&threads[2], NULL, &genOutput, &comms.second);  // Output
      
             void *result;
             pthread_join(threads[0],&result);
             pthread_join(threads[1],&result);
             pthread_join(threads[2],&result);
      
       }
      

      附注:

      除非您对数据的处理有什么非常奇怪的地方。这可能会更快地编写为单线程应用程序。

      【讨论】:

      • 感谢您的回复,这很有帮助。为了解决您的旁注,这是一种非常奇怪的数据处理方式。我正在尝试起草一个模板来处理非常具体的数据文件。作为一个短期目标,我正在尝试优化一个小程序,它以 2 kb 的块接收 2.5 mb 的数据。至于单线程应用程序,我目前有这样编写的程序,只是出于好奇,我想尝试线程,看看速度是否完全不同。
      猜你喜欢
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多