Objektorienterad Realtidsprogrammering Föreläsning 4 Problem i "Concurrent Programming". Mönster för objektorienterad realtidsprogrammering previous next Problem och mönster Sekvensiella beskrivningar trevliga • Som vi har sett är sekvensiella beskrivningar.
Download
Report
Transcript Objektorienterad Realtidsprogrammering Föreläsning 4 Problem i "Concurrent Programming". Mönster för objektorienterad realtidsprogrammering previous next Problem och mönster Sekvensiella beskrivningar trevliga • Som vi har sett är sekvensiella beskrivningar.
Objektorienterad Realtidsprogrammering
2000
Föreläsning 4
Problem i "Concurrent Programming".
Mönster för objektorienterad
realtidsprogrammering
previous
next
Problem och mönster
Sekvensiella beskrivningar trevliga
• Som vi har sett är sekvensiella beskrivningar trevliga
– men det är problematiskt att beskriva aktiviteter som naturligt
har flera parallella aktiviteter som en enda sekvensiell process
– Exempel på sådana situationer är
• skriva och läsa mot gemensam resurs
– bankomat
• system som består av flera samverkande hårdvaror
–
–
–
–
–
previous
next
automatisk dörr
farthållare
microvågsugn
hiss
plastspruta
2
Problem och mönster
...
• Istället kan vi beskriva var och en av aktiviteterna som
en separat process
• Problemet blir mer då att samordna aktiviteterna och
hanteringen av gemensamma (delade) resurser
• Vi har tidigare diskuterat hur detta kan göras med hjälp
av lättviktsprocesser och tex
– semaforer
– monitorer
previous
next
3
Problem och mönster
Konflikter
• Det kan uppstå konflikter då flera processer använder
gemensam resurs, ett par typiska är:
– Läsa-skriv-konflikter
• dvs en process skriver (uppdaterar) en resurs som en annan process
läser
• beroende av ordning mellan processerna blir resultatet olika
– Skriva-skriva-konflikter
• Om två trådar båda försöker skriva på samma resurs så vet man inte
vad resultatet kommer vara vid nästa läsning
previous
next
4
Problem och mönster
Kritiska regioner
• Vi har tidigare sett att om flera trådar kan exekvera samma delar
av ett objekt så kan vi få problem
• Vi kan identifiera kritiska regioner som måste skyddas för att vi
ska få ett förutsägbart resultat
Kritisk
region
class Even {
// Do not use
private int n = 0;
public int next(){ // POST?: next is always even
++n;
++n;
return n;
}
}
• Vad är resultatet om två olika processer anropar next()?
previous
next
5
Problem och mönster
Lås
• För att allokera en viss resurs eller utföra kritisk region i
obruten följd så kan vi använda lås
• I Java har vi möjlighet att använda oss av
synkroniserade metoder eller kod block
– via synchronized
• Man skall dock inte använda lås i onödan då processer
andra processer i onödan kan få vänta på en resurs
– vilket gör att programmet går långsammare
– det medför också en del mer av systemet att hantera en
synkroniserad resurs, vilket också gör det hela långsammare
previous
next
6
Problem och mönster
...
class ExpandableArray {
protected Object[] data; // the elements
protected int size = 0;
// the number of array slots used
// INV: 0 <= size <= data.length
public ExpandableArray(int cap) {
data = new Object[cap];
}
public synchronized int size() {
return size;
}
public synchronized Object get(int i) // subscripted access
throws NoSuchElementException {
if (i < 0 || i >= size )
throw new NoSuchElementException();
return data[i];
}
previous
next
7
Problem och mönster
...
public synchronized void add(Object x)
if (size == data.length) { // need a
Object[] olddata = data;
data = new Object[3 * (size + 1) /
System.arraycopy(olddata, 0, data,
}
data[size++] = x;
}
{ // add at end
bigger array
2];
0, olddata.length);
public synchronized void removeLast()
throws NoSuchElementException {
if (size == 0)
throw new NoSuchElementException();
data[--size] = null;
}
}
previous
next
8
Problem och mönster
Vänta
• För att flera parallellt exekverande trådar om vart annat
skall få exekvera så kan man låta dem sova under vissa
stunder. Medan en tråd sover får en annan tillfälle att
exekvera
• I Java kan man helt enkelt låta aktuell tråd sova genom
att skicka meddelandet sleep till den
sleep(milliseconds);
• En annan möjlighet är att släppa kontrollen via
meddelandet yield()
– Då låter aktuell tråd annan tråd med samma prioritet ta över
previous
next
9
Problem och mönster
Vänta genom att “sova” viss tid
public class SimpleThread extends Thread {
public SimpleThread(String str) {
super(str);
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i + " " + getName());
try {
sleep((long)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}
previous
next
10
Problem och mönster
...
public class TwoThreadsTest {
public static void main (String[] args) {
new SimpleThread("Jamaica").start();
new SimpleThread("Fiji").start();
}
}
• Kan ge något i stil med
0
0
1
1
2
2
3
3
4
4
5
previous
next
Jamaica
Fiji
Fiji
Jamaica
Jamaica
Fiji
Fiji
Jamaica
Jamaica
Fiji
Jamaica
5 Fiji
6 Fiji
6 Jamaica
7 Jamaica
7 Fiji
8 Fiji
9 Fiji
8 Jamaica
DONE! Fiji
9 Jamaica
DONE! Jamaica
11
Problem och mönster
Använd wait och notify
• En annan möjlighet är att låta en process vänta till dess
att en annan process meddelar om att en viss resurs är
tillgänglig
P1
resurs.wait();
P2
resurs.set(i++);
resurs.notify();
print(resurs.get());
• Vi tittar på fler mer konkreta exempel på detta nästa
gång
previous
next
12
Problem och mönster
Dödläge
• Om en process P1 väntar på en resurs som hålls av process P2
innan den kan fortsätta men P2 samtidigt väntar på en resurs som
hålls av P1 innan den kan fortsätta så har vi ett dödläge (eng.
deadlock)
– jmf Joseph Hellers ”Moment 22”
• Def. En process är i dödläge då den väntar på en resurs den aldrig
kan få
• Vi kan rita en resursallokeringsgraf över den ovan beskrivna
situationen
R1
Allocation
Request
P2
P1
Request
previous
next
R2
Allocation
13
Problem och mönster
Exempel: dödläge
class Cell { // Do not use
private long value;
synchronized long getValue() { return value; }
synchronized void setValue(long v) { value = v; }
synchronized void swapValue(Cell other) {
long t = getValue();
long v = other.getValue();
setValue(v);
other.setValue(t);
}
Tråd1
Tråd2
}
Lås a
a.swapValue(b)
Går bra (vi har redan låset) t = getValue()
Vänta på lås för b
previous
next
v = other.getValue()
b.swapValue(a)
Lås b
t = getValue()
Går bra
v = other.getValue()
Vänta på lås för a
14
Problem och mönster
Upptäcka deadlock
• Det går att avgöra om det finns dödlägen genom att
analysera en grafen med avseende på processer och
tillgängliga resurser och sedan se om grafen går att
reducera
• Vi tittar på detta under period 3 av kursen
previous
next
15
Problem och mönster
Missade signaler
• Det kan också hända att ett en process fortsätter sova
pga att den missade en signal om att den kunde fortsätta
– processen började kanske vänta efter att meddelandet om att
det var okey att fortsätta skickades ut
previous
next
16
Problem och mönster
Livelock
• En process försöker om och om igen få tillgång till en
resurs men misslyckas av någon anledning (det kanske
slumpar sig så att någon annan hela tiden hinner före)
– processen kanske kan göra andra saker medan den vid
upprepade tillfällen försöker allokera resursen
– därför är den levande men den blir ändå inte färdig då den
väntar på resursen
previous
next
17
Problem och mönster
Svält (eng. starvation)
• En process får aldrig möjlighet att köra
– det kanske hela tiden finns processer med högre prioritet som
går före
previous
next
18
Problem och mönster
Designmönster; vad, varför, hur?
• Vad?
– Beskrivningar av lyckosamma och bra designlösningar
• Varför?
– Återanvända bra design och expertkunskap.
– Vi formar en vokabulär som gör det enklare att kommunicera lösningar
med andra
– Design diskuteras på ett annat sätt än tidigare
• Hur?
– Halvstandardiserad form som på ett lättillgängligt sätt beskriver bra
designlösningar
• Vi tittar också på en separat uppsättning oh-blad som handlar om
designmönster
previous
next
19
Problem och mönster
Mönster för objektorienterad realtidsprogrammering
• I Lea avsnitt 1.4 beskrivs en del designmönster som är
grundläggande för resten av beskrivningarna i boken
• Det hela är inte presenterat på riktigt vanlig
designmönsterform utan mer som löpande text och
kodexempel
previous
next
20
Problem och mönster
Lager
• Att dela upp kod på lager är vanligt i alla typer av
system
• Ofta använder man sandwiching
before(); method(); after();
– kanske vill man alltid att after-delen utförs
before();
try {method();}
finally {after();}
– en typisk situation lås(); kod(); låsUpp();
previous
next
21
Problem och mönster
Adaptorer
«interface»
Runnable
run
AdaptedPerformer
run
adaptee
Performer
perform
class AdaptedPerformer implements Runnable {
private final Performer adaptee;
public AdaptedPerformer(Performer p) { adaptee = p; }
public void run() { adaptee.perform(); }
}
previous
next
22
Problem och mönster
… adaptor
class AdaptedTank implements Tank {
protected final Tank delegate;
public AdaptedTank(Tank t) { delegate = t; }
public float getCapacity() { return delegate.getCapacity();
}
public float getVolume() { return delegate.getVolume(); }
protected void checkVolumeInvariant() throws AssertionError
{
float v = getVolume();
float c = getCapacity();
if ( !(v >= 0.0 && v <= c) )
throw new AssertionError();
}
previous
next
23
Problem och mönster
...
public synchronized void transferWater(float amount)
throws OverflowException, UnderflowException {
checkVolumeInvariant();
// before-check
try {
delegate.transferWater(amount);
}
// postpone rethrows until after-check
catch (OverflowException ex) { throw ex; }
catch (UnderflowException ex) { throw ex; }
finally {
checkVolumeInvariant(); // after-check
}
}
}
previous
next
24
Problem och mönster
«interface»
Subklassning
Tank
TankImpl
• Template method
SubclassedTank
Superklass
templateMethod()
methodX()
methodY()
Subklass
methodX()
methodY()
previous
next
return methodX() + methodY();
return
return
25
Problem och mönster
…
abstract class AbstractTank implements Tank {
protected void checkVolumeInvariant() throws AssertionError {
// ... identical to AdaptedTank version ...
}
protected abstract void doTransferWater(float amount)
throws OverflowException, UnderflowException;
public synchronized void transferWater(float amount)
throws OverflowException, UnderflowException {
// identical to AdaptedTank version except for inner call:
// ...
try {
doTransferWater(amount);
}
finally {}
// ...
}
}
previous
next
26
Problem och mönster
...
class ConcreteTank extends AbstractTank {
protected final float capacity = 10.f;
protected float volume;
// ...
public float getVolume() { return volume; }
public float getCapacity() { return capacity; }
protected void doTransferWater(float amount)
throws OverflowException, UnderflowException {
// ... implementation code ...
}
}
previous
next
27
Problem och mönster
Metodadaptorer
• Man kan skapa en klass vars enda avsikt är att anropa en
metod
• Denna strategi påminner om mönstren
– Command Object
– Strategy
operationsgränssnitt
previous
interface TankOp {
void op() throws OverflowException, UnderflowException;
}
next
28
Problem och mönster
...
class TankWithMethodAdapter {
// ...
protected void checkVolumeInvariant() throws AssertionError {
// ... identical to AdaptedTank version ...
}
protected void runWithinBeforeAfterChecks(TankOp cmd)
throws OverflowException, UnderflowException {
// identical to AdaptedTank.transferWater
//
except for inner call:
// ...
try {
cmd.op();
}
finally {}
// ...
}
previous
next
29
Problem och mönster
...
protected void doTransferWater(float amount)
throws OverflowException, UnderflowException {
// ... implementation code ...
}
public synchronized void transferWater(final float amount)
throws OverflowException, UnderflowException {
runWithinBeforeAfterChecks(new TankOp() {
public void op()
throws OverflowException, UnderflowException {
doTransferWater(amount);
}
});
skapa klass
och anropa
}
}
previous
next
30