2013-09-06 14 views
8

Ich arbeite an einem Multithread-System, in dem eine Datei basierend auf den Dateizugriffsberechtigungen zwischen verschiedenen Threads geteilt werden kann. Wie kann ich überprüfen, ob die Datei bereits von einem anderen Thread geöffnet wurde? Vielen Dank im VorausWie überprüft man, ob eine Datei bereits in C geöffnet ist

+1

Sie benötigen entweder eine physische Sperre oder definieren ein Semaphor über den Thread (befindet sich in einem gemeinsamen Speicher?) – CppLearner

+2

Am einfachsten ist es, eine gemeinsame Liste aller geöffneten Dateien zu behalten und sie allen Threads zur Verfügung zu stellen. – dasblinkenlight

+1

Nun, der einfachste Weg ist, es selbst zu verfolgen. – Duck

Antwort

3

Sie können int flock(int fd, int operation); verwenden, um eine Datei als gesperrt zu markieren und auch zu prüfen, ob sie gesperrt ist.

Apply or remove an advisory lock on the open file specified by fd. 
    The argument operation is one of the following: 

     LOCK_SH Place a shared lock. More than one process may hold a 
       shared lock for a given file at a given time. 

     LOCK_EX Place an exclusive lock. Only one process may hold an 
       exclusive lock for a given file at a given time. 

     LOCK_UN Remove an existing lock held by this process. 

Herde sollte in einer Gewinde App arbeiten, wenn Sie die Datei separat in jedem Thread öffnen: multiple threads able to get flock at the same time

Es stehen weitere Informationen über Herde und es potenzielle Schwächen here:

+0

Leider wirkt sich dies auch auf andere Prozesse aus, wenn sie versuchen, die Datei zu sperren. Asker scheint Thread-only-Sperre zu wollen. – mvp

+0

Gute Aussage. Ich nahm an, dass er fork/exec tat, aber vielleicht nicht. – dcaswell

2

Um herauszufinden, ob ein Die benannte Datei ist bereits unter geöffnet. Sie können das Verzeichnis /proc/self/fd scannen, um zu sehen, ob die Datei einem Dateideskriptor zugeordnet ist. Das folgende Programm aus Skizzen eine Lösung:

DIR *d = opendir("/proc/self/fd"); 
if (d) { 
    struct dirent *entry; 
    struct dirent *result; 

    entry = malloc(sizeof(struct dirent) + NAME_MAX + 1); 
    result = 0; 
    while (readdir_r(d, entry, &result) == 0) { 
     if (result == 0) break; 
     if (isdigit(result->d_name[0])) { 
      char path[NAME_MAX+1]; 
      char buf[NAME_MAX+1]; 
      snprintf(path, sizeof(path), "/proc/self/fd/%s", 
        result->d_name); 
      ssize_t bytes = readlink(path, buf, sizeof(buf)); 
      buf[bytes] = '\0'; 
      if (strcmp(file_of_interest, buf) == 0) break; 
     } 
    } 
    free(entry); 
    closedir(d); 
    if (result) return FILE_IS_FOUND; 
} 
return FILE_IS_NOT_FOUND; 

Von Ihrem Kommentar, so scheint es, was Sie tun möchten, ist eine vorhandene FILE * abzurufen, wenn man bereits von einem früheren Aufruf von fopen() auf die Datei erstellt wurde. Es gibt keinen Mechanismus, der von der Standard-C-Bibliothek bereitgestellt wird, um alle aktuell geöffneten FILE * zu durchlaufen. Wenn es einen solchen Mechanismus gäbe, könnten Sie seinen Dateideskriptor mit fileno() ableiten und dann /proc/self/fd/# mit readlink() abfragen, wie oben gezeigt.

Dies bedeutet, dass Sie eine Datenstruktur verwenden müssen, um Ihre offenen FILE * s zu verwalten. Wahrscheinlich wäre eine Hash-Tabelle, die den Dateinamen als Schlüssel verwendet, am nützlichsten für Sie.

+0

Ich verwende Dateizeiger nicht den Deskriptor. Also diese Lösung wird mir nicht helfen – user503403

+3

Es gibt 'Fileno (FILE)' Makro, das den Deskriptor vom Dateizeiger zurückgibt. Allerdings würde ich '/ proc/self/fd' nicht einfach scannen, weil es nicht atomar ist - ein anderer Thread kann die Datei trotzdem schließen oder öffnen, während Sie'/proc/self/fd' scannen. – mvp

1

Ich weiß nicht viel in der Art von Multithreading unter Windows, aber Sie haben eine Menge Optionen, wenn Sie unter Linux sind. Here ist eine FANTASTIC Ressource. Sie können auch alle file-locking features offered inherently or explicitly by the OS (zB: fcntl) nutzen. Mehr zu Linux-Schlössern here. Das Erstellen und manuelle Verwalten eigener Mutexe bietet Ihnen mehr Flexibilität als Sie es sonst tun würden. user814064 's Kommentar über flock() sieht aus wie die perfekte Lösung, aber es tut nie weh, Optionen zu haben!

Hinzugefügt ein Codebeispiel:

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 

FILE *fp; 
int counter; 
pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER; 

void *foo() { 
     // pthread_mutex_trylock() checks if the mutex is 
     // locked without blocking 
     //int busy = pthread_mutex_trylock(&fmutex); 

     // this blocks until the lock is released 
     pthread_mutex_lock(&fmutex); 
     fprintf(fp, "counter = %d\n", counter); 
     printf("counter = %d\n", counter); 
     counter++; 
     pthread_mutex_unlock(&fmutex); 
} 

int main() { 

     counter = 0; 
     fp = fopen("threads.txt", "w"); 

     pthread_t thread1, thread2; 

     if (pthread_create(&thread1, NULL, &foo, NULL)) 
       printf("Error creating thread 1"); 
     if (pthread_create(&thread2, NULL, &foo, NULL)) 
       printf("Error creating thread 2"); 

     pthread_join(thread1, NULL); 
     pthread_join(thread2, NULL); 

     fclose(fp); 
     return 0; 
} 
+0

Beachten Sie, dass Nur-Link-Antworten auf SO NICHT willkommen sind. – mvp

+0

Korrigiert. Danke und Entschuldigung. – collinjsimpson

0

Wenn Sie es in der Schale neigen zu tun, können Sie einfach lsof $filename verwenden.

+1

Dies ist inhärent Threads unsicher - sobald es zurückgibt, kann sich die Antwort ändern. – Stewart

Verwandte Themen