簡體   English   中英

使用 readdir 在 for 循環中並行遞歸

[英]Parallelizing recursion in a for-loop using readdir

我想並行化一個 C 程序,該程序使用 OpenMP 和 C 遞歸計算目錄及其子目錄的大小。

我的問題是,當我使用opendir進入目錄並使用readdir遍歷子目錄時,我只能一個接一個地訪問它們,直到到達最后一個子目錄。 這一切都按順序運作良好。

然而,當並行化程序時,我認為將子目錄的數量分成兩半(甚至更小的分區)並使用 OpenMp 任務通過子目錄遞歸是有意義的。

顯然,由於 for 循環的結構,我不能簡單地將問題大小(= 子目錄的數量)分成兩半,並且這樣的循環不能使用#pragma omp for並行化。

有人知道如何將此 function 拆分為任務嗎? 任何幫助將不勝感激。

這是我的一些代碼(我已經刪除了我認為與這個問題無關的部分。)

int calculate_folder_size(const char *path) {

    struct stat sb;

    if (S_ISREG(sb.st_mode)) { // if it's a file, not a directory (base case)
        return sb.st_size;
    }

    DIR *folder = opendir(path);

    struct dirent *element;
    size_t size = 4096;

    for (element = readdir(folder); element != NULL; element = readdir(folder)) {

   //(...)
            if (element->d_type == DT_DIR) {
                // recursive call of calculate_folder_size
                size += calculate_folder_size(name);
            } else {
             //(...)
            }
        }
    }
    closedir(folder);
    return size;
}

您需要一個支持 OpenMP 任務的現代編譯器,它從等式中刪除了 Visual C++。 如果您使用的是這樣的編譯器,您需要做的就是將對calculate_folder_size()的遞歸調用轉換為 OpenMP 任務:

int calculate_folder_size(const char *path) {
    struct stat sb;

    if (S_ISREG(sb.st_mode)) { // if it's a file, not a directory (base case)
        return sb.st_size;
    }

    DIR *folder = opendir(path);

    struct dirent *element;
    size_t size = 4096;

    for (element = readdir(folder); element != NULL; element = readdir(folder)) {
        //(...)
        if (element->d_type == DT_DIR) {
            // Make sure the task receives a copy of the path
            char *priv_name = strdup(name); // (1)
            // recursive call of calculate_folder_size
            //               (2)
            #pragma omp task shared(size) firstprivate(priv_name)
            {
                // (3)
                #pragma omp atomic update
                size += calculate_folder_size(priv_name);
                free(priv_name); // (4)
            }
        } else {
            //(...)
        }
    }
    // (5)
    #pragma omp taskwait

    closedir(folder);
    return size;
}

這里的重要部分是:

  1. 您需要向任務傳遞一個名稱參數,該參數將一直存在並保留其值,直到任務被執行,這可能是將來的任何時間。 因此,您需要復制name ,例如,使用strdup(3)

  2. 任務應該記住priv_name的當前值,因為它將在循環的下一次迭代中改變。 因此,首先對firstprivate進行priv_name處理。 它還需要能夠在父上下文中修改size ,因此為它shared

  3. 由於所有任務都在更新父 scope 中的相同size變量,因此需要使用atomic update來保護訪問。

  4. 不再需要私有名稱,必須對其進行處置。

  5. 在返回size之前,父任務應該等待所有子任務首先完成。

必須從並行區域內調用此 function 才能並行完成其工作:

int size;

#pragma omp parallel
#pragma omp single
size = calculate_folder_size("/some/path");

限制事物仍然並行運行的並行深度可能是一個好主意。 我把它留給你弄清楚如何:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM