0

Ich erstelle ein Programm, das alle #include Abhängigkeiten zwischen C-Dateien in einem angegebenen Verzeichnis und seinen untergeordneten Verzeichnissen rekursiv findet. Abhängigkeitspfade sollten absolut sein, daher verwende ich realpath, um relative Pfade und symbolische Links aufzulösen. Da es viele Dateien geben kann, habe ich beschlossen, das Programm Multithread mit OpenMP oder Pthreads zu machen.C Multithreading und realpath

Das Problem besteht darin, dass realpath Pfade durch das Arbeitsverzeichnis auflöst. Alle Threads teilen sich das gleiche Arbeitsverzeichnis, also müsste ich einen Mutex auf chdir und realpath setzen.

Gibt es eine alternative Standardfunktion für realpath, die auch das Verzeichnis zum Auflösen des Pfads als Argument verwendet?

+1

Warum nicht jeden Thread eine Zeichenfolge ihres aktuellen Pfads relativ zu Ihrem Startverzeichnis beibehalten? Sie können es jedes Mal anhängen, wenn Sie in ein Unterverzeichnis absteigen, und ein Level entfernen, wenn Sie herauskommen. Normalerweise sehen Sie nur relative Pfade, wie '#include" common/util.h "'. Sie müssen durch die Include-Pfade "-I" gelöst werden, die Sie dem Compiler geben. Ohne diese Informationen sehe ich nicht, wie Sie die vollständigen Pfade trotzdem korrekt auflösen. – e0k

+0

Sie haben Recht, das ist wahrscheinlich die Lösung, mit der ich gehen werde. Es löst nicht Symlinks, aber wirklich wer Symlinks enthalten Dateien ..? Danke, dass du mich gebracht hast - ich denke daran, ich werde das auch reparieren. –

+0

Viele Leute symlink Header. Oder zumindest haben einige der größeren Projekte, an denen ich gearbeitet habe, Header aus verschiedenen Gründen (viele von ihnen nicht sehr gut, aber das ist es, was in 30 Jahren passiert). –

Antwort

2

Es gibt eine Reihe von POSIX-Funktionen mit dem Suffix at (z. B. openat()), die mit einem angegebenen Verzeichnis arbeiten. Es gibt jedoch keine realpathat() Funktion in POSIX. Es gibt auch keine opendirat(), aber es gibt fdopendir(), die einen DIR Stream für einen offenen Verzeichnisdateideskriptor erstellt.

In einem Multithread-Programm ist jede Verwendung von chdir() angespannt.

Sie sollten Ihren Algorithmus überdenken, um die verschiedenen *at()-Funktionen zu verwenden, damit Sie das Verzeichnis überhaupt nicht ändern müssen. Sie öffnen die Verzeichnisse zum Lesen (open() oder openat() mit O_DIRECTORY, vielleicht - obwohl O_DIRECTORY ist nicht 100% notwendig, noch wird es auf MacOS unterstützt), so dass Sie dann auf die Dateien mit dem Verzeichnis-Datei-Deskriptor in der *at() entsprechend zugreifen können Anrufe.

+0

Wird dies mein Problem lösen? –

+0

Ich glaube schon, aber ich habe noch keinen Code, um es zu zeigen. –

0

Ich arbeitete ein bisschen an einer Lösung. Es ist keineswegs optimal, aber zumindest scheint es zu funktionieren. Ich habe die Funktion abspathat erstellt, die einen relativen Pfad in einen absoluten Pfad umwandelt. Dann benutze ich das eingebaute readlinkat um die Symlinks zu reparieren. Die Lösung behandelt Pfade wie "../code.c" "./code.c" "code.c" in "/dir/code.c". Momentan werden jedoch keine Pfade wie z. B. ../dir/../code.c repariert, aber warum sollte jemand einen solchen Pfad erstellen? Es prüft auch nicht, ob die Datei tatsächlich existiert. Fühlen Sie sich frei, diesen Code zu verbessern oder zu tun, was Sie wollen.

#include <string.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <dirent.h> 
#include <stdio.h> 
/*****************************************************************************/ 
char *abspathat(char *dirpath, int dirlen, char *path); 
/*****************************************************************************/ 
static const int MAX_FILEPATH = 4096; 
/*****************************************************************************/ 
char *realpathat(int dirfd, char *dirpath, int dirlen, char *path) { 
    char *abs = abspathat(dirpath, dirlen, path); 
    char *buf = malloc(sizeof(char)*MAX_FILEPATH); 
    ssize_t size = readlinkat(dirfd, abs, buf, MAX_FILEPATH); 
    char *realpath; 
    if(size != -1) { 
     realpath = malloc(sizeof(size+1)); 
     memcpy(realpath, buf, size); 
     realpath[size] = '\0'; 
     free(abs); 
    } else { 
     realpath = abs; 
    } 
    free(buf); 
    return realpath; 
} 
/*---------------------------------------------------------------------------*/ 
char *abspathat(char *dirpath, int dirlen, char *path) { 
    /* If absolute */ 
    if(path[0] == '/') { 
     return path; 
    } 
    int i; 
    char *right; 
    int d = 0; 
    int rlen = strlen(path); 
    int llen = 0; 
    if(path[0] == '.') { 
     if(path[1] == '.' && path[2] == '/') { 
      for(i = 3, d = 1; path[i] == '.' 
        && path[i+1] == '.' 
        && path[i+2] == '/' 
        && i < rlen; i+=3) { 
       d++; 
      } 
      right = &path[i]; 
      rlen -= i; 
     } else if(path[1] == '/') { 
      right = &path[2]; 
      rlen -= 2; 
     } 
    } else { 
     right = &path[0]; 
    } 
    for(i = dirlen - 1 - (dirpath[dirlen-1] == '/'); d && i; i--) { 
     if(dirpath[i] == '/') { 
      d--; 
     } 
    } 
    llen = i+1; 
    char *cpy = malloc(sizeof(char)*(llen + rlen + 2)); 
    memcpy(cpy, dirpath, llen); 
    cpy[llen] = '/'; 
    memcpy(cpy+llen+1, right, rlen); 
    cpy[llen+rlen+1] = '\0'; 
    return cpy; 
} 
/*---------------------------------------------------------------------------*/ 
int main(int argc, char *argv[]) { 
    if(argc == 3) { 
     char *dirpath = argv[1]; 
     DIR *d = opendir(dirpath); 
     char *path = argv[2]; 
     char *resolved = realpathat(dirfd(d), dirpath, strlen(dirpath), path); 
     printf("%s\n", resolved); 
    } else { 
     printf("realpathat [directory] [filepath]\n"); 
    } 
    return 0; 
}