【问题标题】:How to write to file from different threads, OpenMP, C++如何从不同的线程、OpenMP、C++ 写入文件
【发布时间】:2017-09-23 23:31:00
【问题描述】:

我使用 openMP 来并行我的 C++ 程序。我的并行代码有非常简单的形式

#pragma omp parallel for shared(a, b, c) private(i, result)
        for (i = 0; i < N; i++){
         result= F(a,b,c,i)//do some calculation
         cout<<i<<" "<<result<<endl;
         }

如果两个线程同时尝试写入文件,数据就会混淆。 我该如何解决这个问题?

【问题讨论】:

  • 同步
  • 不要在多个线程中写入。

标签: c++ parallel-processing openmp


【解决方案1】:

OpenMP 提供编译指示来帮助进行同步。 #pragma omp critical 任何时候只允许一个线程执行附加语句(互斥临界区)。 #pragma omp ordered pragma 确保循环迭代线程按顺序进入该区域。

// g++ -std=c++11 -Wall -Wextra -pedantic -fopenmp critical.cpp
#include <iostream>

int main()
{
  #pragma omp parallel for
  for (int i = 0; i < 20; ++i)
    std::cout << "unsynchronized(" << i << ") ";
  std::cout << std::endl;
  #pragma omp parallel for
  for (int i = 0; i < 20; ++i)
    #pragma omp critical
    std::cout << "critical(" << i << ") ";
  std::cout << std::endl;
  #pragma omp parallel for ordered
  for (int i = 0; i < 20; ++i)
    #pragma omp ordered
    std::cout << "ordered(" << i << ") ";
  std::cout << std::endl;
  return 0;
}

示例输出(通常每次都不同):

unsynchronized(unsynchronized(unsynchronized(05) unsynchronized() 6unsynchronized() 1unsynchronized(7) ) unsynchronized(unsynchronized(28) ) unsynchronized(unsynchronized(93) ) unsynchronized(4) 10) unsynchronized(11) unsynchronized(12) unsynchronized(15) unsynchronized(16unsynchronized() 13unsynchronized() 17) unsynchronized(unsynchronized(18) 14unsynchronized() 19) 
critical(5) critical(0) critical(6) critical(15) critical(1) critical(10) critical(7) critical(16) critical(2) critical(8) critical(17) critical(3) critical(9) critical(18) critical(11) critical(4) critical(19) critical(12) critical(13) critical(14) 
ordered(0) ordered(1) ordered(2) ordered(3) ordered(4) ordered(5) ordered(6) ordered(7) ordered(8) ordered(9) ordered(10) ordered(11) ordered(12) ordered(13) ordered(14) ordered(15) ordered(16) ordered(17) ordered(18) ordered(19) 

【讨论】:

  • 如果只是将数据写入文件,使用最后的方法,可以加快速度吗?我问是因为对我来说,如果线程按顺序执行循环,那么它是否等于串行执行?
  • @AdityaG 可能仍然可以并行加速,因为有序的 pragma 不需要应用于整个循环体,例如:#pragma omp parallel for ordered \n for int (i = 0; i &lt; 20; ++i) { do parallel work; #pragma omp ordered \n { do ordered serial output; } do more parallel work; }
  • 我测试了你的代码,只是为了写的情况。我没有“做并行工作”,而只有 for 循环中的有序语句。无论我在这个有序的编译指示中做什么,并行编译总是很慢(虽然只有一点)。与有序 pragma 中的工作相比,只有在并行完成大量工作时,这种方法才有用。
【解决方案2】:

问题是:你有一个所有线程都试图访问的资源。必须保护那些单一资源免受并发访问(线程安全资源也这样做,只是对您透明;顺便说一句:here 是关于 std::cout 线程安全的一个很好的答案)。您现在可以保护这个单一资源 e。 G。带有std::mutex。那么问题是,线程将不得不等待互斥锁,直到另一个线程再次将其返回。所以只有当 F 是一个非常复杂的函数时,你才能从并行化中获益。

另一个缺点:由于线程并行工作,即使使用互斥锁来保护 std::in,结果也可以按任意顺序打印出来,具体取决于哪个线程恰好更早运行。

如果我可能假设您希望 F(... i) 的结果在较大 i 的结果之前用于较小的 i,那么您应该完全放弃并行化或以不同的方式进行:

提供一个大小为N 的数组,并让每个线程将其结果存储在那里(array[i] = f(i);)。然后在一个单独的非并行循环中迭代数组。同样,只有当 F 是一个复杂函数(并且对于大 N)时,这样做才值得付出努力。

另外:请注意,线程也必须被创建,这会在某处造成一些开销(创建线程基础结构和堆栈,在操作系统上注册线程,... - 除非您可以重用之前已经在线程池中创建的一些线程...)。在决定是否要并行化时也要考虑这一点。有时,非并行计算可以更快...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    • 1970-01-01
    相关资源
    最近更新 更多