Czytelnicy i pisarze - semafor

0

Hej,

Próbuję napisać program, który rozwiązuje problem czytelników i pisarzy. Czy jest to możliwe do zrobienia na jednym semaforze? Udało mi się zrealizować program, w którym uruchamiam dwa wątki, jeden sobie działa, a drugi rozpoczyna działanie dopiero po zakończeniu pracy tego pierwszego. Ale chyba nie o to tutaj chodzi. Być może nie do końca rozumiem ideę tego problemu, stąd moje pytanie o jeden semafor.

1

Raczej chodzi o to, że dwa wątki pracują jednocześnie i czasem mogą odwoływać do wspólnego zasobu.
Na pewno można to zrobić na jednym semaforze: gdy akurat nie ma czytelników, to pisarz dostaje dostęp. Ale nie jest to dobre rozwiązanie, bo pisarz może zostać zagłodzony. http://www.mif.pg.gda.pl/homepages/marcin/PWIR2015-16/pwir-2.pdf#page=13

0

OK, pojęcie zagłodzenia jest mi znane. Z tego co widzę, to tam użyty jest semafor binarny, w dodatku w ilości dwóch :)

Jeśli chodzi o ten wspólny zasób: jak mogę to zobrazować? Mam problem z jakimś wyobrażeniem sobie tego :)

0

Rzeczywiście, ale można to zrobić na jednym semaforze niebinarnym. //chyba jednak nie można :P (a przynajmniej ja nie umiem)
Przykład:
mamy jakiś plik/rekord w bazie, w którym zapisane są informacje. Pisarz zaczyna go aktualizować. Jeżeli w tym samym czasie czytelnik będzie go czytał, to część odczytanych informacji może być nowa, a część stara - z tego mogą być grube problemy.

0

Czyli wygląda na to, że każdy wątek musi mieć własny semafor? Ewentualnie myślałem jeszcze o rozwiązaniu opartym o monitory. Ale póki co chcę pobawić się w semafory.

OK, to też rozumiem. Tylko jak można zasymulować taki zasób? Nie chcę bawić się w tworzenie bazy. Potrzebuję wykonać prostą implementację.

1

Jeżeli chodzi o ten kod z linku, to jeden semafor czytanie wspólny dla wszystkich wątków czytających i jeden pisanie wspólny dla wszystkich czytających i piszących.

Zasymulować można tak: obiekt z kilkoma polami, na którym będzie wykonywane czytanie i pisanie. Czytanie normalnie: foo.bar, ale pisanie robić przez metodę foo.setBar(...). W metodzie setBar przed ustawieniem wartości można uśpić na chwilę wątek. Dzięki temu aktualizacja wszystkich wartości rozciągnie się trochę w czasie, a czytanie będzie bardzo szybkie. Jeżeli pisarz będzie pisał, a czytelnik w tym czasie przeczyta obiekt, to dostanie głupoty.

0

OK, zaimplementowałem sobie rozwiązanie, gdzie czytelnicy są preferowani, a pisarze mogą być zagłodzeni (i to działa, pisarze czasami dostają dostęp, ale czytelnicy są "górą"). Następnie próbowałem zaimplementować sytuację odwrotną, czyli gdzie pisarze są preferowani, a czytelnicy mogą być zagłodzeni i tu mam problem. Kod wygląda tak:

def writer(self):
    while True:
        logging.info('Writer starts to write...')    
        sem_wrt.acquire()
        self.wrt_count += 1
        if self.wrt_count == 1:
            sem_rdr_try.acquire()
        sem_wrt.release()
        sem_book.acquire()
        logging.info('Writing...')
        time.sleep(randint(1,3))
        logging.info('Writing finished...')
        sem_book.release()
        sem_wrt.acquire()
        self.wrt_count -= 1
        if self.wrt_count == 0:
            sem_rdr_try.release()
        sem_wrt.release()

Po uruchomieniu okazuje się, że czytelnicy tylko raz czytają, a następnie gdy próbują znowu dostać się do zasobu, to nie jest to możliwe (czekam kilkanaście minut obserwując to co się dzieje i żaden czytelnik nie pojawia się niestety). Testy robiłem puszczając dwa wątki pisarzy i dwa czytelników, taka konfiguracja sprawdzała się w przypadku sytuacji odwrotnej, czyli gdzie czytelnicy są preferowani. Co może być nie tak?

0

Zanim zedytowałeś posta, rozwiązać można to było przez "statyczną" zmienną:

def reader():
    #...
    reader.rdr_count += 1
    #...

reader.rdr_count = 0

Co do aktualnego problemu, to spróbuj sprawdzić, gdzie czytelnicy się przywieszają. Być może jest to po prostu zagłodzenie, być może wynika z tego, że preferowani pisarze mają duże opóźnienie. Zanim jeden skończy pisać drugi już czeka w kolejce.

1 użytkowników online, w tym zalogowanych: 0, gości: 1