2012-09-05 15 views
6

Rozważmy następującą aplikację: serwer wyszukiwania, który po uruchomieniu tworzy duży indeks stron internetowych oparty na danych odczytanych z dysku. Po zainicjalizowaniu indeksu w pamięci nie można modyfikować, a wiele wątków jest uruchamianych w celu obsługi zapytań użytkowników. Załóżmy, że serwer jest skompilowany do natywnego kodu i używa wątków systemu operacyjnego.Czy jest to możliwe do wdrożenia prymitywów współbieżności systemu Linux, które zapewniają lepszą izolację niż wątki, ale porównywalną wydajność?

Teraz model gwintowania nie zapewnia izolacji między wątkami. Wątek buggy lub dowolny kod niezwiązany z wątkiem może uszkodzić indeks lub uszkodzoną pamięć, która została przydzielona i logicznie należy do innego wątku. Takie problemy są trudne do wykrycia i debugowania.

Teoretycznie Linux pozwala wymusić lepszą izolację. Po zainicjowaniu indeksu pamięć, którą zajmuje, może być oznaczona jako tylko do odczytu. Wątki można zastąpić procesami, które współdzielą indeks (pamięć współdzieloną), ale inne niż te mają oddzielne stosy i nie mogą się wzajemnie uszkadzać. Nielegalne operacje są automatycznie wykrywane przez sprzęt i system operacyjny. Żadne muteksy ani inne operacje podstawowe synchronizacji nie są potrzebne. Wyścigi danych związane z pamięcią są całkowicie eliminowane.

Czy taki model jest możliwy do zastosowania w praktyce? Czy zdajesz sobie sprawę z jakiejkolwiek aplikacji z prawdziwego życia, która robi takie rzeczy? A może istnieją pewne podstawowe trudności, które sprawiają, że taki model jest niepraktyczny? Czy uważasz, że takie podejście wprowadziłoby obciążenie wydajnościowe w porównaniu z tradycyjnymi wątkami? Teoretycznie używana pamięć jest taka sama, ale czy istnieją problemy związane z implementacją, które spowalniałyby działanie?

+0

Z pewnością istnieje aplikacja, która używa mmap do oznaczania różnych obszarów pamięci jako tylko do odczytu. Jednak zazwyczaj dzieje się tak ze względu na wydajność, a nie w celu ochrony przed błędnym kodem. – Gray

+0

Chociaż z pewnością nie chcę rozpoczynać wojny religijnej, przejście na używanie języka (takiego jak Java), który obsługuje naprawdę niezmienne typy, rozwiązałoby wiele problemów z "błędnymi wątkami", które "psują pamięć". – Gray

+2

Uszkodzenie pamięci w programach wielowątkowych występuje nie tylko wtedy, gdy wątek zapisuje się w losowej lokalizacji w pamięci (takie błędy są stosunkowo łatwe do uniknięcia i wykrywane), ale także wtedy, gdy wątek uzyskuje poprawne odniesienie do obiektu, który nie jest bezpieczny dla wątków i który jest używany przez jakiś inny wątek. Takie błędy są znacznie trudniejsze do uniknięcia i wykrycia i mogą wystąpić w dowolnym programie wielowątkowym, bez względu na język. –

Odpowiedz

4

Oczywistym rozwiązaniem jest nie używanie w ogóle nici. Użyj oddzielnych procesów. Ponieważ każdy proces ma wiele wspólnego z strukturami kodu i strukturą tylko do odczytu, udostępnianie danych tylko do odczytu jest banalne: sformatuj je zgodnie z potrzebami dla użycia w pamięci w pliku i zmapuj plik do pamięci.

Stosując ten schemat, tylko zmienna na dane procesowe byłaby niezależna. Kod byłby udostępniony, a dane zainicjowane statycznie byłyby udostępniane do momentu ich zapisania. Jeśli proces zachodzi, nie ma wpływu na inne procesy. Brak problemów z współbieżnością.

0

Myślę, że może Cię zainteresować memcached. Można również utworzyć pamięć współużytkowaną i otworzyć ją jako tylko do odczytu, a następnie utworzyć wątki. Nie powinno to powodować znacznego obniżenia wydajności.

1

Możesz użyć mprotect(), aby indeks był tylko do odczytu. W systemie 64-bitowym możesz mapować pamięć lokalną dla każdego wątku pod losowym adresem (patrz this Wikipedia article on address space randomization), co powoduje, że prawdopodobieństwo uszkodzenia pamięci z jednego wątku dotyka innego astronomicznie małego (i oczywiście każde uszkodzenie, które nie trafi w zapamiętywaną pamięć w ogóle spowoduje a segfault). Oczywiście musisz mieć różne stosy dla każdej nitki.

+0

Czy wątki mogą mieć różne sterty, czy też różne sterty odróżniają wątki od procesów? –

+0

Kupa jest właśnie tam, gdzie 'malloc' dostaje swoją pamięć. Aby nadać różnym wątkom różne stosy, po prostu wymaga, aby każdy wątek losował z innej puli (używając danych specyficznych dla wątku).Potrzebujesz odpowiedniej biblioteki malloc z odpowiednimi opcjami. –

+0

Problem polega na tym, że pomysł randomizacji sterty zapobiegałby tylko jednej klasie błędów - uszkodzeniu pamięci z powodu zapisu do losowych lokalizacji. Jak napisałem w innych komentarzach, takie błędy są stosunkowo łatwiejsze do zapobieżenia i wykrycia. Większym problemem są wyścigi danych, których całkowita izolacja całkowicie wyeliminowałaby. Powiedzmy, że jeden wątek wywołuje funkcję, która zwraca wskaźnik do niezabezpieczonego wątkiem obiektu statycznego. Jeśli inny wątek wywołuje tę samą funkcję, masz wyścig danych i nie pomaga, że ​​zwracany wskaźnik jest losowy. Wskaźnik nie został odgadnięty, że został uzyskany za pomocą ważnego wywołania. –