Ik zit nu al een paar dagen met een irritant probleem. De situatie is als volgt: Er is een aantal Worker threads die berekeningen uitvoeren. Deze worden beheerd door de WorkerManager. De simulatie (want daar is het voor) gebeurd in rondes. Er zijn een aantal berekeningen die uitgevoerd moeten worden (gesimuleerd door reqReports). Als deze berekeningen 'op' zijn moeten de Workers wachten totdat er weer nieuwe berekeningen zijn. De nieuwe berekeningen worden weer klaargezet door de method WorkerManager.step. Deze step functie wordt extern, door de simulatieclass aangeroepen worden. Dit mag echter pas gebeuren zodra alle Workers klaar zijn met hun werk c.q. al het werk voor de ronde gedaan is.
Het eerste gedeelte, het laten wachten van de Workers todat er weer werk is, krijg ik voorelkaar. Het laten wachten van de simulatie op het voltooien van al het werk echter niet. Hieronder heb ik twee sets code, een waarbij er een sleep is ingebouwd voor elke step om, erg karig, de block te simuleren. Wat ik al gedaan heb om de steps te blocken:
Deze monitor klasse is zodat ik niet zelf bij elke aanroep een lock op hoef te vragen.
Ik hoop dat jullie kunnen zeggen of ik ergens een grote denkfout maak, of gewoon in compleet de verkeerde richting zit te denken en dat er een veel makkelijkere, robustere oplossing is. Want ik zie het even niet meer.
Het eerste gedeelte, het laten wachten van de Workers todat er weer werk is, krijg ik voorelkaar. Het laten wachten van de simulatie op het voltooien van al het werk echter niet. Hieronder heb ik twee sets code, een waarbij er een sleep is ingebouwd voor elke step om, erg karig, de block te simuleren. Wat ik al gedaan heb om de steps te blocken:
- Het gebruik van de eigen monitor om te wachten, dit werkt natuurlijk niet aangezien die ook gebruikt wordt om te wachten bij het dispensen.
- Het toevoegen van een extra monitor, binnen de Manager, waarop gewait wordt als een step wordt aangeroepen, en waar dan een notify of notifyall (beiden geprobeerd) naar geroepen wordt op het moment dat de laatste Worker zijn werk inlevert.
- Wat nachtelijk gepruts met semaphoren
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public class Simulation extends Thread { private WorkerManager wm; private boolean run; public Monitor stepMonitor; public Simulation() { wm = new WorkerManager(this); run = true; stepMonitor = new Monitor(); } public void run() { System.out.println("Starting simulation"); wm.firstStep(); System.out.println("Done with first step"); while(run) { try { sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } // stepMonitor.wacht(); wm.step(); } System.out.println("Ending simulation"); } } |
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| public class WorkerManager { // private Simulation simulation; private volatile int reqReports; private LinkedList<Worker> workers; public WorkerManager(Simulation aSimulation) { workers = new LinkedList<Worker>(); int workerCount = 2; for (int i=0; i<workerCount; i++) { workers.add(new Worker(this)); } // simulation = aSimulation; reqReports = 200; } public synchronized List<Object> dispense() { System.out.println("Dispensing"); if (reqReports <= 0) { try { System.out.println("Waiting on new resources"); wait(); } catch (InterruptedException e) { e.printStackTrace(); } } List<Object> result = new LinkedList<Object>(); return result; } public synchronized void reportIn(List<Object> list) { System.out.println(""+reqReports); --reqReports; // if (reqReports==0) { // System.out.println("Reached end of round. Notifying for next step."); // simulation.stepMonitor.verwittigAllen(); // } } public synchronized void step() { System.out.println("Stepping"); // do stuff // if (reqReports == 0) { // try { simulation.stepMonitor.wacht(); } // catch (InterruptedException e) { e.printStackTrace(); } // } // Reset conditions reqReports = 200; // Vertel de Workers dat ze weer verder kunnen notifyAll(); } public synchronized void firstStep() { for (int i=0; i<workers.size(); i++) { workers.get(i).start(); } } } |
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| public class Worker extends Thread{ private WorkerManager wm; public Worker(WorkerManager aWM) { wm = aWM; } public void run() { while (true) { List<Object> list = wm.dispense(); wm.reportIn(list); } } } |
Deze monitor klasse is zodat ik niet zelf bij elke aanroep een lock op hoef te vragen.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
| public class Monitor { public synchronized void wacht() throws InterruptedException { wait(); } public synchronized void verwittig() { notify(); } public synchronized void verwittigAllen() { notifyAll(); } } |
Ik hoop dat jullie kunnen zeggen of ik ergens een grote denkfout maak, of gewoon in compleet de verkeerde richting zit te denken en dat er een veel makkelijkere, robustere oplossing is. Want ik zie het even niet meer.
C'est le ton qui fait la musique. | Blog | @linkedin
R8 | 18-55 IS | 50mm 1.8 2 | 70-200 2.8 APO EX HSM | 85 1.8