czytelnik, pisarz , wątpliwość

0

Cześć :)
Rozważmy kod:

Monitor ReadersNWriters {
  int WaitingWriters, WaitingReaders,NReaders, NWriters;
  Condition CanRead, CanWrite;

 Void BeginWrite()
  {
        if(NWriters == 1 || NReaders > 0)
        {
              ++WaitingWriters;
             wait(CanWrite);
             --WaitingWriters;
        }
        NWriters = 1;
  }
  Void EndWrite()
  {
         NWriters = 0;
         if(WaitingReaders)
              Signal(CanRead);
         else
              Signal(CanWrite);
  }
Void BeginRead()
  {
       if(NWriters == 1 || WaitingWriters > 0)
       {
             ++WaitingReaders;
             Wait(CanRead);
	--WaitingReaders;
       }
       ++NReaders;
       Signal(CanRead);
  }

  Void EndRead()
  {
        if(--NReaders == 0)
                Signal(CanWrite);

  }

Wszystko ok, poza jednym. Jest to rozwiązanie opierające się o monitory. Zatem, dlaczego nie są używane locki, a jedynie zmienne warunkowe? To w końcu jak tu zapewniona jest synchronizacja?

1

Przecież są obiekty typu Condition.

0

tak. Nie rozumiem co masz na myśli

1

Co to jest za język?

Na pewno nie jest to Java.

1

Na Condition da się synchronizować: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html

Zresztą, jak zasugerował przedmówca, kod słabo przypomina poprawny kod Javowy.

0

tak, bo to jest pseudokod.
Mhm, czyli rozumiem, że używając samych zmiennych Condition możemy już uzyskać oczekiwany efekt. W sumie to tak. W takim razie jaka jest zasadniczo różnica między lockami a Conditionami?
P.S. Ale właściwie to Ty dałeś linka w którym są właśnie locki.

0

Bo Condition to nie zmienna warunkowa tylko coś zbindowane do konkretnego Locka. Coś w stylu kolejki oczekiwania. Przynajmniej tak to zrozumiałem z dokumentacji.

0

Czyli w końcu potrzeba locków czy nie potrzeba?

0

No w jakiś sposób zsynchronizować trzeba. W Javie Condition jest zbindowane do Locka, więc by użyć Condition trzeba mieć najpierw Locka.

0

dobrze. Ala jak mam niby lockować w czytelniku, jak ja mam wpusczać ich wielu, a nie jednego?

0

Procedura BeginRead blokuje tylko wtedy gdy są jacyś piszący lub czekający pisarze.

0

w jakim celu ma blokować? Nie lepiej żeby zasnęła na kolejce? ( na zmiennej condition?)

0

No dokładnie chodziło mi o czekanie.

0

Do implementacji czytelników/pisarzy (maksymalnie jeden może na raz pisać, wiele może czytać, ale nie, gdy ktoś pisze) najlepiej wykorzystać:

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReadWriteLock.html

0

no to czyli czytelnik blokuje ma locku?

0

czy w takim razie, następująca implementacja wpusczania i wypuszczania czytelnika jest dobra?

  public void wpuscCzytelnika() {
        

            while (liczbaPisarzyBibioteka == 1) {
                room.awaitUninterruptibly();
            }
            liczbaCzytelnikowBibioteka++;
            room.signal();
        
    }


    public void wypuscCzytelnika() {
        try{
            liczbaCzytelnikowBibioteka--;
        }finally{
        if( liczbaCzytelnikowBibioteka == 0){
            room.signal();
        }
        }
    }


1

Nie. Twoja implementacja nie ma szansy zadzialac. Probowales to w ogole uruchomic zanim napisales posta?

  1. Twoj pseudokod wprowadza wiecej niejasnosci niz tlumaczy. Dla klarownosci uzywaj kodu Java.
  2. Czytelnik nie uzyskuje locka przed await() w metodzie wpuscCzytelnika(). Zgaduje ze skonczy sie to IllegalMonitorStateException
  3. Wprowadziles race condition na polach liczbaPisarzyBibioteka i liczbaCzytelnikowBiblioteka
  4. Wprowadziles race condition na polach WaitingReaders i WaitingWriters.

Nie wiem jak wyobrazasz sobie implementacje czegos co dziala jak ReadLock za pomoca Condition. Condition jest nierozerwalnie zwiazany z Lockiem, a lock implikuje mutual exclusion. Postaraj sie przeczytac ze zrozumieniem Javadoc dla Condition i Lock. Masz rowniez ewidentny problem ze zrozumieniem ze monitor nie jest substytutem locka, tylko jego fundamentalna czescia. Sa locki i semafory. Lock wpuszcza tylko jeden watek, a semafor okreslona ich ilosc. Do kontroli kolejki oczekujacych watkow potrzebny jest monitor. To wszystko.
Internet pelen jest przejrzystych, prostych, lepszych od mojego tlumaczen na temat tego czym jest lock. Wystarczy poszukac.

Ponizej implementacja i test

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Book {

    public volatile long writes = 0L;
    public volatile long reads = 0L;

    public boolean moreThanOneWriter = false;
    public boolean moreThanOneReader = false;

    private final Lock lock = new ReentrantLock();
    private final Condition canRead = lock.newCondition();
    private final Condition canWrite = lock.newCondition();

    private boolean ongoingWrite;
    private int concurrentReaders;

    public void write() {
        lock.lock();
        try {
            while (concurrentReaders > 0 || ongoingWrite) canWrite.awaitUninterruptibly();
            if (ongoingWrite) moreThanOneWriter = true;
            ongoingWrite = true;
            writes++;
        } finally {
            ongoingWrite = false;
            canRead.signalAll();
            lock.unlock();
        }
    }

    public long read() {
        lock.lock();
        try {
            while (ongoingWrite) canRead.awaitUninterruptibly();
            if (++concurrentReaders > 1) moreThanOneReader = true;
            reads++;
            return writes;
        } finally {
            concurrentReaders--;
            canWrite.signal();
            lock.unlock();
        }
    }
}
import org.junit.Test;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.LockSupport;

import static org.junit.Assert.*;

public class BookTest {

    private static final int WRITERS = 3;
    private static final int READERS = 5;
    private static final long ITERATIONS = 5_000_000L;

    @Test
    public void bookTest() throws InterruptedException {
        final CountDownLatch latch = new CountDownLatch(WRITERS + READERS);
        final Book book = new Book();

        for (int i = 0; i < WRITERS; i++) new Writer(book, ITERATIONS, latch).start();
        for (int i = 0; i < READERS; i++) new Reader(book, ITERATIONS, latch).start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("Writes: " + book.writes);
                    System.out.println("Reads: " + book.reads);
                    LockSupport.parkNanos(1_000_000_000L);
                }
            }
        }.start();

        latch.await();

        assertEquals(WRITERS * ITERATIONS, book.writes);
        assertEquals(READERS * ITERATIONS, book.reads);
        assertFalse(book.moreThanOneWriter);
        assertFalse(book.moreThanOneReader);
    }

static class Writer extends Thread {

        private final Book book;
        private long writesLeft;
        private final CountDownLatch latch;

        Writer(final Book book, final long writes, final CountDownLatch latch) {
            this.book = book; this.writesLeft = writes; this.latch = latch;
        }

        @Override
        public void run() {
            while (--writesLeft >= 0) book.write();
            latch.countDown();
        }
    }

    static class Reader extends Thread {

        private final Book book;
        private long readsLeft;
        private final CountDownLatch latch;

        Reader(final Book book, final long reads, final CountDownLatch latch) {
            this.book = book; this.readsLeft = reads; this.latch = latch;
        }

        @Override
        public void run() {
            while (--readsLeft >= 0) book.read();
            latch.countDown();
        }
    }
    
}

Powinno dzialac tak samo bez Condition.

0

Przeczytałem, że lock uniemożliwa jednoczense wykonywanie kodu przez dwa lub więcej wątków jednocześnie. W takim razie jak blokując tu:

public void write() {
        lock.lock();

Załóżmy, że wejdzie jeden czytelnik. Zablokuje on za sobą locka i drugi już nie wejdzie?

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