2012-02-15 14 views
11

Chcę móc blokować na podstawie hierarchii systemu plików. NpHierarchiczne blokady muteksu w Javie

gwintu 1:

lock("/"); 
doStuff(); 
unlock(); 

gwintu 2:

lock("/sub/foo"); 
doStuff(); 
unlock(); 

gwintu 3:

lock("/sub/bar"); 
doStuff(); 
unlock(); 

przypadku gwintu 1 uzyskuje blokady pierwszy wtedy nici 2 i 3 jest być zablokowane, dopóki wątek 1 nie zostanie odblokowany. Jeśli jednak wątek 2 uzyska najpierw blokadę, wówczas wątek 3 powinien być w stanie wykonać w tym samym czasie co wątek 2. Ogólna zasada jest taka, że ​​jeśli istnieje blokada katalogu nadrzędnego, wówczas wątek musi blokować.

Czy Java ma wbudowane coś, co może pomóc rozwiązać ten problem? Chcę uniknąć przechowywania blokady na katalog, ponieważ będą setki tysięcy katalogów.

+0

+1 za bardzo interesujące pytanie. Czy struktura katalogów jest określona z góry, czy też "pliki" mogą być tworzone ad-hoc? Co to jest system priorytetów, jeśli jeden wątek chce uzyskać katalog główny, podczas gdy wiele innych wątków próbuje uzyskać pojedyncze pliki?Czy wątek, który chce, aby root był głodny, czy jest jakaś gwarancja, którą masz na myśli? – templatetypedef

+0

Zakładam, że jeśli wątek 2 nabywa blokadę, wątek 1 powinien blokować, prawda? – Irfy

+0

Częścią motywacji jest zmodyfikowanie systemu plików, aby ścieżki stale się zmieniały. Nie jestem pewien, jak poradzić sobie z głodem gwintu ... to jest coś, czego tak naprawdę nie brałem pod uwagę. Przypuszczam, że mechanizm blokady odczytu/zapisu może być bliski rozwiązania tego problemu i być w stanie obsłużyć nie głodujące wątki. –

Odpowiedz

7

bym przechowywania ścieżek katalogów w drzewie tak:

-/
- sub 
    - foo 
    - bar 

Gdy trzeba zablokować coś w tym drzewie zejść z korzenia i nabyć odczyt blokady na wszystko z wyjątkiem tarczy sam węzeł. Węzeł docelowy otrzymuje blokadę zapisu.

Ten schemat gwarantuje ci brak stabilności - stabilność i stabilność odpowiednich części drzewa.

Nie widzę konkretnego problemu z przechowywaniem setek tysięcy zamków. Prawdopodobnie zmarnuje to prawdopodobnie 100 bajtów pamięci RAM na blokadę. Ale upraszcza architekturę. Czy mierzysz, czy to rzeczywiście jest problem?

Alternatywnie możesz mieć mapę ze ścieżki do zablokowania. Wszystkie operacje w tym słowniku muszą być synchronizowane przez osoby dzwoniące. To pozwala leniwie inicjować blokady. Możesz także okresowo wyrzucać śmieci do nieużywanych blokad, najpierw robiąc blokadę zapisu na root, który wygasza wszystkie operacje. Gdy wszystko jest w porządku, odrzucasz wszystkie blokady inne niż root.

+1

Fajne podejście. Myślę, że to może zadziałać. Jeśli muszę przechowywać blokadę na katalog, to niech tak będzie. Po prostu starałem się tego uniknąć, jeśli to możliwe. –

+0

Tak właśnie bazy danych blokują. Blokują ścieżkę B-drzewa od korzenia do stron liści. – usr

+0

To wygląda dobrze. Poszedłbym z 'java.util.ConcurrentHashMap' dla najlepszej wydajności i zamieniłbym go na' '. Chciałbym również użyć 'File file = new File (stringPath) .getCanonicalFile()', aby zagwarantować wyjątkowość. Logika powinna być wtedy dość jasna, biorąc pod uwagę tworzenie leniwych blokad i osobne blokowanie do odczytu i zapisu. – Irfy

0

Może istnieć bardziej wydajne rozwiązanie, ale oto jak zacząć.

Chciałbym utworzyć wspólny obiekt TreeAccess, z metodą lock(path) i unlock(path). Ta metoda musiałaby wprowadzić zsynchronizowany blok, który będzie pętlą, dopóki ścieżka nie będzie dostępna. Przy każdej iteracji, jeśli nie jest dostępna, sprawdzałaby, czy ścieżka jest dostępna, a jeśli nie, wait() do czasu, aż inne wątki wywołają notifyAll(). Jeśli ścieżka jest dostępna, będzie kontynuowana, a po zakończeniu wywołaj metodę unlock(), która byłaby notifyAll().

Przed kontynuowaniem należy zapisać zablokowaną ścieżkę w strukturze danych. Przed powiadomieniem musisz usunąć odblokowaną ścieżkę z tej struktury danych. Aby sprawdzić, czy ścieżka jest dostępna, musisz sprawdzić, czy istnieje pewna ścieżka w tej strukturze danych, która jest równa lub jest przodkiem ścieżki, którą chcesz zablokować.

public void lock(String path) { 
    synchronized (lock) { 
     while (!available(path)) { 
      lock.wait(); 
     } 
     lockedPaths.add(path); 
    } 
} 

public void unlock(String path) { 
    synchronized (lock) { 
     lockedPaths.remove(path); 
     lock.notifAll(); 
    } 
} 

private boolean available(String path) { 
    for (String lockedPath : lockedPaths) { 
     if (isParentOrEqual(lockedPath, path) { // this method is left as an exercise 
      return false; 
     } 
    } 
    return true; 
} 
Powiązane problemy