Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.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++;Fork-Join并行阻塞_C++_Multithreading_Parallel Processing - Fatal编程技术网

C++ C++;Fork-Join并行阻塞

C++ C++;Fork-Join并行阻塞,c++,multithreading,parallel-processing,C++,Multithreading,Parallel Processing,假设您希望并行运行一个部分,然后合并回主线程,然后并行返回到该部分,依此类推。类似于童年游戏的红灯绿灯 我已经给出了一个我正在尝试做的例子,我使用一个条件变量在开始时阻止线程,但是希望并行地启动它们,但是在结束时阻止它们,这样它们就可以串行地打印出来。*=操作可能是一个跨越数秒的更大操作。重用线程也很重要。使用任务队列可能太重 我需要使用某种阻塞结构,它不仅仅是一个普通的忙循环,因为我知道如何用忙循环解决这个问题 英文: 线程1创建10个被阻塞的线程 线程1向所有线程发出启动信号(互不阻塞) 线

假设您希望并行运行一个部分,然后合并回主线程,然后并行返回到该部分,依此类推。类似于童年游戏的红灯绿灯

我已经给出了一个我正在尝试做的例子,我使用一个条件变量在开始时阻止线程,但是希望并行地启动它们,但是在结束时阻止它们,这样它们就可以串行地打印出来。*=操作可能是一个跨越数秒的更大操作。重用线程也很重要。使用任务队列可能太重

我需要使用某种阻塞结构,它不仅仅是一个普通的忙循环,因为我知道如何用忙循环解决这个问题

英文:

  • 线程1创建10个被阻塞的线程
  • 线程1向所有线程发出启动信号(互不阻塞)
  • 线程2-11处理它们的独占内存
  • 线程1正在等待2-11完成(此处可以使用原子计数)
  • 螺纹2-11完成,如有必要,每个螺纹可通知1检查其状况
  • 线程1检查其状态并打印阵列
  • 线程1将2-11重新签名以再次处理,从2继续
  • 示例代码(根据cplusplus.com上的示例改编的Naive):

    //条件变量示例
    #include//std::cout
    #include//std::thread
    #包括//std::mutex、std::unique\u lock
    #include//std::condition\u变量
    #包括
    std::互斥mtx;
    std::条件变量cv;
    bool ready=false;
    std::原子计数(0);
    bool end=false;
    INTA[10];
    void doublea(整数id){
    当(!结束){
    标准:唯一锁定lck(mtx);
    而(!ready)cv.wait(lck);
    a[id]*=2;
    计数。取加(1);
    }
    }
    void go(){
    标准:唯一锁定lck(mtx);
    就绪=正确;
    cv.通知所有人();
    ready=false;//天真
    而(count.load()<10)睡眠(1);
    对于(int i=0;i<10;i++){
    
    std::cout您可以使用barrier或condition变量启动所有线程。然后线程可以等待所有线程结束其工作(通过所有线程上的join方法,它是阻塞的)然后在一个循环中打印他们的数据。

    有效地实现它并不是那么简单。此外,除非您正在学习这个主题,否则它没有任何意义。条件变量在这里不是一个好的选择,因为它不能很好地伸缩

    我建议你看看成熟的运行时库是如何实现fork-join并行的,并从中学习或在你的应用程序中使用它们


    OpenMP是与您所寻找的最接近的模型,并且它具有最有效的fork-join屏障实现。尽管如此,它也有其缺点,因为它是为HPC设计的,并且缺乏动态可组合性。TBB和Cilk最适合嵌套并行性以及可在外部pa环境中使用的模块和库中的使用所有区域。

    为什么
    count
    是原子的?为什么一边使用条件变量,另一边使用忙睡眠?@UmNyobe我明确不想使用忙睡眠。线程应该在等待通知时睡眠。对于你的另一个问题,count是原子的,因为幸运的话,它可以一次增加多个线程。IncrMENT是一个两阶段的过程。这不是一个解决方案,因为线程连接后需要重新创建。你说我正在尝试学习是正确的。我以前看过TBB和OpenMP,但OpenMP大量使用pragmas令人不快,TBB有很多锅炉板来做简单的事情。不过我很乐意再给他们一个l阅读并使用它们。为了真正阅读我的问题,我会给你答案。你不想在下面混合前端(使用模型)和运行库。你可以为这些运行时中的任何一个编写自己的前端。
    // condition_variable example
    #include <iostream>           // std::cout
    #include <thread>             // std::thread
    #include <mutex>              // std::mutex, std::unique_lock
    #include <condition_variable> // std::condition_variable
    #include <atomic>
    
    std::mutex mtx;
    std::condition_variable cv;
    bool ready = false;
    std::atomic<int> count(0);
    
    bool end = false;
    int a[10];
    
    void doublea (int id) {
      while(!end) {
        std::unique_lock<std::mutex> lck(mtx);
        while (!ready) cv.wait(lck);
        a[id] *= 2;
        count.fetch_add(1);
      }
    }
    
    void go() {
      std::unique_lock<std::mutex> lck(mtx);
    
      ready = true;
      cv.notify_all();
      ready = false; // Naive
    
      while (count.load() < 10) sleep(1);
      for(int i = 0; i < 10; i++) {
        std::cout << a[i] << std::endl;
      }
    
      ready = true;
      cv.notify_all();
      ready = false;
      while (count.load() < 10) sleep(1);
      for(int i = 0; i < 10; i++) {
        std::cout << a[i] << std::endl;
      }
    
      end = true;
      cv.notify_all();
    }
    
    int main () {
      std::thread threads[10];
      // spawn 10 threads:
      for (int i=0; i<10; ++i) {
        a[i] = 0;
        threads[i] = std::thread(doublea,i);
      }
    
      std::cout << "10 threads ready to race...\n";
      go();                       // go!
    
      return 0;
    }