【问题标题】:How to continue work with master while threads execute for loop iterations?如何在线程执行循环迭代时继续使用master?
【发布时间】:2021-04-21 21:21:42
【问题描述】:

我被要求用 C 语言编写一个 OpenMP 程序,以便主线程将工作分配给其他线程,当它们在执行任务时,主线程应该定期检查它们是否完成,如果没有,它应该增加一个共享变量。

这是线程任务的函数:

void work_together(int *a, int n, int number, int thread_count) {
#   pragma omp parallel for num_threads(thread_count) \
        shared(a, n, number) private(i) schedule(static, n/thread_count)
    for (long i=0; i<n; i++) {
        // do a task, such as:
        a[i] = a[i] * number;
    }
}

它是从 main 调用的:

int main(int argc, char *argv[]) {
    int n = atoi(argv[1]);
    int arr[n];
    initialize(arr, n);

    // this will be the shared variable
    int number = 2;
    work_together(arr, n, number, thread_count);

    //I want to write a function or an if to check whether threads are still working
    /* if (threads_still_working()) {
        number++;
        sleep(100);
    }
    */

    printf("There are %d threads\n", omp_get_num_threads());
}

thread_count被初始化为4,我尝试对大的n(>10000)执行它,但是主线程会一直等待其他线程完成for循环的执行,并且会只有在work_together() 返回时才继续主线程:printf() 将始终打印只有一个线程在运行。

现在,有什么方法可以从主线程检查其他线程是否仍在运行,如果它们还在运行,则进行一些递增?

【问题讨论】:

    标签: c multithreading performance parallel-processing openmp


    【解决方案1】:

    OpenMP standard可以阅读:

    当一个线程遇到一个并行结构时,一组线程被 创建以执行并行区域。 遇到的线程 并行构造成为新团队的主线程, 在新并行区域的持续时间内线程数为零。 新团队中的所有线程,包括主线程,执行 region. 团队创建后,团队中的线程数 在该平行区域的持续时间内保持不变。

    因此,使用子句 #pragma omp parallel for num_threads 所有线程都将执行并行工作(计算循环的迭代),这是您不想要的。为了解决这个问题,您可以实现

    的部分功能
    `#pragma omp parallel for num_threads`
    

    因为,显式使用上述子句将使编译器自动在团队中的线程之间划分循环的迭代,包括该团队的主线程。代码如下所示:

    # pragma omp parallel num_threads(thread_count) shared(a, n, number)
    {
          int thread_id = omp_get_thread_num();
          int total_threads = omp_get_num_threads();
          if(thread_id != 0) // all threads but the master thread
          {
            thread_id--; // shift all the ids
            total_threads = total_threads - 1;
            for(long i = thread_id ; i < n; i += total_threads) {
                // do a task, such as:
                a[i] = a[i] * number;
            }
          }
    } 
    

    首先,我们确保除了 master (ie, if(thread_id != 0)) 之外的所有线程都执行要并行化的循环,然后我们将循环的迭代分配给其余线程(i.e.,for(int i = thread_id ; i &lt; n; i += total_threads))。我选择了 chunk=1 的静态分布,你可以选择不同的,但你必须相应地调整循环。

    现在您只需将逻辑添加到:

    现在,有什么方法可以从主线程检查 其他线程仍在运行,如果它们还在运行,是否进行一些递增?

    为了不泄露太多,我将添加您必须转换为真实代码的伪代码以使其工作:

    // declare two shared variable 
    // 1) to count the number of threads that have finished working count_thread_finished
    # pragma omp parallel num_threads(thread_count) shared(a, n, number)
    {
          int thread_id = omp_get_thread_num();
          int total_threads = omp_get_num_threads();
          if(thread_id != 0) // all threads but the master thread
          {
            thread_id--; // shift all the ids
            total_threads = total_threads - 1;
            for(long i = thread_id ; i < n; i += total_threads) {
                // do a task, such as:
                a[i] = a[i] * number;
            }
            // count_thread_finished++
          }
          else{ // the master thread 
              while(count_thread_finished != total_threads -1){
                  // wait for a while....
              }
         }
    } 
    

    但是请记住,由于变量 count_thread_finished 在线程之间共享,因此您需要确保 mutual exclusion例如, 使用 omp atomic)更新,否则您会有一个竞态条件。这应该足以让您继续前进。

    顺便说一句:schedule(static, n/thread_count) 几乎不需要,因为默认情况下,大多数 OpenMP 实现已经将循环的迭代(在线程之间)划分为连续的块。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      • 2018-12-30
      • 1970-01-01
      相关资源
      最近更新 更多