动态数组C++上的OpenMP多写

pvabu6sv  于 2023-01-01  发布在  其他
关注(0)|答案(1)|浏览(158)

通过使用OpenMP,我试图并行化这样定义的字典的创建。

typedef struct Symbol {
    int usage;
    char character; 
} Symbol;

typedef struct SymbolDictionary {
    int charsNr; 
    Symbol *symbols; 
} SymbolDictionary;

我做了下面的代码。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <omp.h>

static const int n = 10;

int main(int argc, char* argv[]) {
  int thread_count = strtol(argv[1], NULL, 10);
    omp_set_dynamic(0);
    omp_set_num_threads(thread_count);

  SymbolDictionary **symbolsDict = calloc(omp_get_max_threads(), sizeof(SymbolDictionary*));
  SymbolDictionary *dict = NULL;
  int count = 0; 
  #pragma omp parallel for firstprivate(dict, count) shared(symbolsDict)
  for (int i = 0; i < n; i++) {
    if (count == 0) {
      dict = calloc(1, sizeof(SymbolDictionary));
      dict->charsNr = 0;
      dict->symbols = calloc(n, sizeof(Symbol));

      #pragma omp critical
      symbolsDict[omp_get_thread_num()] = dict;
    }

    dict->symbols[count].usage = i;
    dict->symbols[count].character = 'a' + i;
    ++dict->charsNr;
    ++count;
  }

  if (omp_get_max_threads() > 1) {
    // merge the dictionaries
  }

  for (int j = 0; j < symbolsDict[0]->charsNr; j++)
    printf("symbolsDict[0][%d].character: %c\nsymbolsDict[0][%d].usage: %d\n",
      j,
      symbolsDict[0]->symbols[j].character,
      j,
      symbolsDict[0]->symbols[j].usage);

  for (int i = 0; i < omp_get_max_threads(); i++)
    free(symbolsDict[i]->symbols);
  
  free(symbolsDict);
  return 0;
}

代码编译并运行,但我不确定omp块是如何工作的,我是否正确地实现了它,特别是我必须在循环开始时将dictsymbolsDict附加在一起,因为我不知道线程何时完成它的工作。通过这样做,可能不同的线程将同时写入symbolsDict内部,但是写入到不同的存储器中。虽然线程将使用不同的访问点,但是dict对于每个线程应该是不同的,我不确定这是个好办法。
我用不同的线程测试了代码,创建了不同大小的字典。我没有遇到任何问题,但也许这只是偶然。
基本上我在文档中寻找理论部分。所以我想知道我是否正确地实现了代码?如果没有,什么是不正确的,为什么?

jgwigjjp

jgwigjjp1#

不同的线程会同时在不同的内存中写入symbolsDict。虽然线程会使用不同的访问点,但是每个线程的dict应该是不同的,我不确定这是不是一个好的方法。
这不是一个好方法,但它是安全的。一个更干净的方法是这样的:

SymbolDictionary **symbolsDict = calloc(
      omp_get_max_threads(), sizeof(SymbolDictionary*));

#pragma omp parallel
{
    SymbolDictionary *dict = calloc(1, sizeof(SymbolDictionary));
    int count = 0;
    dict->charsNr = 0;
    dict->symbols = calloc(n, sizeof(Symbol));
    symbolsDict[omp_get_thread_num()] = dict;
#   pragma omp for nowait
    for(int i = 0; i < n; i++) {
        dict->symbols[count].usage = i;
        dict->symbols[count].character = 'a' + i;
        ++dict->charsNr;
        ++count;
    }
}

请注意,内部杂注是omp for,而不是omp parallel for,因此它使用外部parallel块来分配其工作。nowait是一种性能改进,它避免了循环末尾的线程障碍,因为它是并行部分的最后一部分,并且线程无论如何都会在该部分末尾等待所有其他线程。

相关问题