Ich lerne die gleichzeitige Programmierung in Java und schreibe eine Simulation für Game of Life.
Hier ist was ich denke:
Jetzt wird es Streit an den gemeinsamen Grenzen der Segmente geben. Wenn ein Thread den Zustand einer Grenzzelle überschrieb, bevor sein Nachbar den vorherigen Wert gelesen hat, wird die Berechnung des Nachbarn falsch sein.
Was sind meine Optionen?
Meine Frage ist, gibt es eine andere Möglichkeit, mit den Konflikten an den Grenzzellen umzugehen, die kein Kopieren von Daten beinhalten oder effizienter ist als die beiden oben genannten Optionen? Kann ReaderWriterLock, volatile Variable oder andere Synchronisierungsmechanismen verwendet werden?
UPDATE: Bis jetzt das doppelte Pufferlösung von Peter ist die sauberste. Aber ich habe eine Frage. Da die beiden Arrays gemeinsame Daten sind und wir keine Synchronisation verwenden (synchronisierter Zugriff oder flüchtige Variable), wird dadurch kein Sichtbarkeitsproblem verursacht ? Können mehrere CPUs die Array-Werte zwischenspeichern und bei jeder Iteration nur einen Teil des Arrays aktualisieren? Dann erhalten die Threads veraltete Werte für die Grenzzellen. Ist das möglich? Wenn nicht, warum. Wenn ja, wie löse ich es? Es scheint, zwei volatile Arrays zu deklarieren wird ihre einzelnen Elemente nicht volatil machen .
Ich schlage vor, 2 int [] [] Arrays zu haben. Nennen wir sie A und B. A wird die Werte aller ungeraden "Ticks" enthalten und B wird die geradzahligen Ticks enthalten.
Initialisiere A auf deinen ursprünglichen Zustand. Lassen Sie dann Ihre Threads los, um den nächsten Zustand jeder Zelle zu berechnen, und platzieren Sie die Ergebnisse in die entsprechende Zelle in B. Sobald alle Ihre Threads fertig sind, haben Sie Ihren neuen Zustand in B. Verwenden Sie nun B, um den nächsten Zustand jeder Zelle zu berechnen, und speichern Sie die Ergebnisse in A. Zu jeder Zeit wird ein Array nur gelesen, und das andere schreib nur, so wird es nie Streit geben.
Vorteile:
Nachteile:
Es beantwortet nicht Ihre eigentliche Frage, aber meine Empfehlung wäre Ihre erste Option ... die neuen Werte zurückgegeben zu haben, anstatt dass die Worker-Threads sie aktualisieren. Ich würde noch einen Schritt weiter gehen und den "Aggregator" dazu bringen, die Ergebnisse der Worker-Threads in ein neues Board-State-Array zu kombinieren und dann das erste zu verwerfen. Mein Argument ist, dass es die allgemeine Lesbarkeit der Logik verbessern wird, da es wenig oder gar keine "globalen Interaktionen" geben wird, um die Sie sich sorgen müssen.
Davon abgesehen bin ich ein bisschen voreingenommen, weil ich es vorziehe, auf eine funktionale Weise zu programmieren, außer wenn es einen starken Grund gibt, das nicht zu tun.
Ich würde den folgenden Ansatz versuchen:
Speicher, der für eine n x m
Kachel benötigt wird, ist 2 * (n + m - 1)
, also benötigen im Allgemeinen größere Kacheln (8x8 oder mehr) proportional weniger Speicher für die zwischengespeicherten Werte.
Ich bin gerade auf java.util.concurrent.Exchanger<V>
gestoßen. Es fungiert als ein Austauschpunkt. Ich kann es wahrscheinlich verwenden, um Listen von Zellenzuständen zwischen benachbarten Threads auszutauschen. Das wäre besser als eine Barriere, weil ich nur zwischen benachbarten Arbeitern synchronisieren muss.
Es beantwortet nicht Ihre eigentliche Frage, aber meine Empfehlung wäre Ihre erste Option ... die neuen Werte zurückgegeben zu haben, anstatt dass die Worker-Threads sie aktualisieren. Ich würde noch einen Schritt weiter gehen und den "Aggregator" dazu bringen, die Ergebnisse der Worker-Threads in ein neues Board-State-Array zu kombinieren und dann das erste zu verwerfen. Mein Argument ist, dass es die allgemeine Lesbarkeit der Logik verbessern wird, da es wenig oder gar keine "globalen Interaktionen" geben wird, um die Sie sich sorgen müssen.
Davon abgesehen bin ich ein bisschen voreingenommen, weil ich es vorziehe, auf eine funktionale Weise zu programmieren, außer wenn es einen starken Grund gibt, das nicht zu tun.
Um Ihr Update über das Caching-Problem mit Double-Buffering zu beantworten, ist das kein Problem. CPUs haben kohärenten Cache und sie wissen, wann Daten in einem anderen CPU-Cache geändert wurden.
Ich schlage vor, 2 int [] [] Arrays zu haben. Nennen wir sie A und B. A wird die Werte aller ungeraden "Ticks" enthalten und B wird die geradzahligen Ticks enthalten.
Initialisiere A auf deinen ursprünglichen Zustand. Lassen Sie dann Ihre Threads los, um den nächsten Zustand jeder Zelle zu berechnen, und platzieren Sie die Ergebnisse in die entsprechende Zelle in B. Sobald alle Ihre Threads fertig sind, haben Sie Ihren neuen Zustand in B. Verwenden Sie nun B, um den nächsten Zustand jeder Zelle zu berechnen, und speichern Sie die Ergebnisse in A. Zu jeder Zeit wird ein Array nur gelesen, und das andere schreib nur, so wird es nie Streit geben.
Vorteile:
Nachteile:
Ich würde den folgenden Ansatz versuchen:
Speicher, der für eine %code% Kachel benötigt wird, ist %code% , also benötigen im Allgemeinen größere Kacheln (8x8 oder mehr) proportional weniger Speicher für die zwischengespeicherten Werte.
Ich lerne die gleichzeitige Programmierung in Java und schreibe eine Simulation für Game of Life.
Hier ist was ich denke:
Jetzt wird es Streit an den gemeinsamen Grenzen der Segmente geben. Wenn ein Thread den Zustand einer Grenzzelle überschrieb, bevor sein Nachbar den vorherigen Wert gelesen hat, wird die Berechnung des Nachbarn falsch sein.
Was sind meine Optionen?
Meine Frage ist, gibt es eine andere Möglichkeit, mit den Konflikten an den Grenzzellen umzugehen, die kein Kopieren von Daten beinhalten oder effizienter ist als die beiden oben genannten Optionen? Kann ReaderWriterLock, volatile Variable oder andere Synchronisierungsmechanismen verwendet werden?
UPDATE: Bis jetzt das doppelte Pufferlösung von Peter ist die sauberste. Aber ich habe eine Frage. Da die beiden Arrays gemeinsame Daten sind und wir keine Synchronisation verwenden (synchronisierter Zugriff oder flüchtige Variable), wird dadurch kein Sichtbarkeitsproblem verursacht ? Können mehrere CPUs die Array-Werte zwischenspeichern und bei jeder Iteration nur einen Teil des Arrays aktualisieren? Dann erhalten die Threads veraltete Werte für die Grenzzellen. Ist das möglich? Wenn nicht, warum. Wenn ja, wie löse ich es? Es scheint, zwei volatile Arrays zu deklarieren wird ihre einzelnen Elemente nicht volatil machen .
Tags und Links java multithreading synchronization conways-game-of-life java-memory-model