czytelnicy i pisarze

0
public class Czytelnia  {

	private int numberOfReader = 0;
	private int numberOfWriters = 0;



	private ReadWriteLock RWlock = new ReentrantReadWriteLock(true);

	public void readerEnter() {

		RWlock.readLock().lock();
		try {
			
			numberOfReader++;
			
		
		} finally {
			RWlock.readLock().unlock();
		}

	}


	public void writerEnter() {

		RWlock.writeLock().lock();
		try {
			
			
			numberOfWriters++;
		
		} finally {
			RWlock.writeLock().unlock();
		}
	}


	public void readerExit() {
		RWlock.readLock().lock();
		try {
			numberOfReader--;
		
		} finally {
			RWlock.readLock().unlock();
		}
	}


	public void  writerEnter(){
		RWlock.writeLock().lock();
		try {
			numberOfWriters--;
			
		} finally {
			RWlock.writeLock().unlock();
		}
	}

Czy to jest poprawnie napisany problem czytelników i pisarzy?
Zakładamy, że wątek czytelnika działa tak:

readerEnter()/ writerEnter();
czytaj/pisz;
readerExit()/writerEnter();

Chodzi też o to, żeby nie dochodziło do zagłodzeń i żeby była zachowana uczciwość.

1
  1. Masz race condition na numberOfReader. ReadLock, jak sama nazwa wskazuje sluzy do odczytywania (wartosci modyfikowanych za pomoca WriteLock).
  2. numberOfWriters zawsze bedzie tylko 1 albo 0. Ale zakladam ze o to Ci chodzilo

Zakładamy, że wątek czytelnika działa tak:
readerEnter()/ writerEnter();
czytaj/pisz;
readerExit()/writerEnter();

Najpierw piszesz ze chodzi o sekwencje dla watku czytelnika. Potem wstawiasz readEnter()/writeEnter(), co zdaje sie odwolywac rowniez do zachowania pisarzy. A na samym koncu writeEnter() jest powtorzone. Kompletnie nie rozumiem o co chodzi.

Chodzi też o to, żeby nie dochodziło do zagłodzeń i żeby była zachowana uczciwość.

Uczciwosc masz w miare zagwarantowana przez zastosowanie fair sync dzieki przekazaniu wartosci true do konstruktora.
Inna kwestia jest ze fair sync jest skandalicznie niewydajny; ale jest to generyczny problem kazdego sprawiedliwego locka.

0

Dziękuje za odpowiedź :)
Załóżmy, że mamy następujący kod:

public class Czytelnia  {
 
    private int numberOfReader = 0;
    private int numberOfWriters = 0;
 
 
 
    private Lock lock = new ReentrantLock(true);
 
    public void readerEnter() {
 
     lock.lock();
        try {
 
            numberOfReader++;
 
 
        } finally {
            lock.unlock();
        }
 
    }
 
 
    public void writerEnter() {
 
        lock.lock();
        try {
 
 
            numberOfWriters++;
 
        } finally {
            lock.unlock();
        }
    }
 
 
    public void readerExit() {
        lock.lock();
        try {
            numberOfReader--;
 
        } finally {
     lock.unlock();
        }
    }
 
 
    public void  writerEnter(){
        lock.lock();
        try {
            numberOfWriters--;
 
        } finally {
 lock.unlock();
        }
    }

Czy dobrze, myślę że ten kod będzie działa w takim sensie, że będzie synchronizowany dostęp do czytelni, ale nie będzie to prawidłowe rozwiązanie. To znaczy, czytelnik będzie zachowywał się dokładnie tak jak pisarz. Bo chodzi o to, że czytelnik wchodząc ( jeżeli nikt nie zajął blokady) zabiera zamek i nikt inny nie może wejść, a powinniśmy zezwalać drugiemu czytelnikowi wejść. Dopiero gdy wyjdzie jeden czytelnik ( lock.unlock() ) to będzie mógł wejść kolejny. Czy rozumowanie jest prawidłowe?

1

Chyba zrozumialem o co chodzi z tym Twoim tlumaczeniem z poprzedniego postu jak to ma dzialac w praktyce. Jesli zalozyles sobie ze watki beda uzyskiwaly dostep do sekcji krytycznej pomiedzy wywolaniami *Enter() a *Exit() to znaczy ze do tej pory nie zrozumiales jak dziala lock i zasada mutual exclusion (MUTEX).
Stanowczo polecam uwazne zapoznanie sie z definicja mutexa na wikipedii i javadociem dla java.util.concurrent.locks.Lock.

0

wiem jaka jest definicja.
Po prostu tam gdzie zamykamy mutex to ten kod "pod spodem" będzie synchronizowany. Dopóki mutexa nie otworzymy to tego fragmentu kodu żaden inny wątek nie będzie mógł wykonać. Wedle tego schematu:
readerEnter()/ writerEnter();
czytaj/pisz;
readerExit()/writerEnter();
W 1 linii "przygotowujemy" funkcję pod pisanie i takie "przygotowanie" działa synchronicznie. Ale już samo pisanie/czytanie nie jest w żaden sposób chronione. Bo przed pisaniem oddajemy mutex więc sama procedura czytania jest synchronizowana. Czy teraz Ci udowodniłem, że przynajmniej mniej więcej wiem jak to działa?
P.S Odpowiedz też na 2. posta mojego.

0
  1. Nie wiem co to znaczy zamknac albo otworzyc mutexa. Mozna go co najwyzej pozyskac i zwolnic. Nie uzywajmy mylacych pojec.
  2. Nie rozumiem co to jest kod "pod spodem"
  3. Znowu w przedstawionej przez Ciebie sekwencji dwukrotnie pojawia sie witerEnter(). Czemu ma to sluzyc?
  4. Co to znaczy "przygotowujemy funkcje pod pisanie"?
  5. W jednym zdaniu piszesz ze pisanie/czytanie nie jest w zaden sposob chronione (co pokrywa sie z kodem) a w nastepnym twierdzisz juz ze procedura pisania jest synchronizowana.

Wydaje mi sie ze musisz sobie na spokojnie podejsc do tematu jeszcze raz. To wszystko sprawia wrazenie jakbys przeczytal 2 pierwsze zdania ze wstepu do programowania wspolbieznego i stwierdzil: "aaa, kumam o co chodzi. to ja zaczne juz pisac kod". To jest najtrudniejsza, najbardziej zlozona i najmniej intuicyjna dziedzina inzynierii oprogramowania. Nie uda Ci sie jej opanowac bez zrozumienia fundamentalnych pojec i zasad.

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