I am learning concurrent programming in java, and writing a simulation for Game of Life.
Here is what I am thinking:
Now there is going to be contention at the common borders of the segments. If a thread overwrote the state of a border cell before its neighbor has read the previous value, the neighbor's calculation is going to be wrong.
What are my options?
My question is, is there any other way to deal with the contention at the border cells that does not involve copying data or is more efficient that the above two options? May be using ReaderWriterLock, volatile variable or other synchronizing mechanism?
UPDATE: So far the double buffering solution by Peter is the cleanest one. But I have a question. Since the two arrays are shared data and we are not using any synchronization (synchronized access or volatile variable), won't it create visibility problem? Could multiple CPUs cache the array values and update only a part of the array with each iteration? Then the threads will get stale values for the border cells. Is this possible? If not, why. If yes, how do I solve it? It seems declaring two arrays volatile will not make their individual elements volatile.
I suggest having 2 int[][] arrays. Let's call them A and B. A will hold the values of all odd numbered "ticks" and B will hold the even numbered ticks.
Initialize A to whatever your initial state looks like. Then let your threads loose to calculate the next state of each cell, and place the results in the corresponding cell in B. Once all your threads are done, you have your new state in B. Now, use B to calculate the next state of each cell, and store the results in A. At any given time, one array will be read only, and the other write only, so there will never be any contention.
Advantages:
Disadvantages:
It doesn't answer your actual question, but my recommendation would be your first option... having the new values returned rather than having the worker threads update them. I'd take it a step further and have the "aggregator" combine the results from the worker threads into a new board state array and then discard the first one. My reasoning being that it will improve the overall readability of the logic, since there will be little to no "global interactions" you have to worry about.
That being said, I'm a bit biased because I prefer to program in a functional manner except when there's a strong reason not to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With