Multithreading synchronization problem

Started by
4 comments, last by IceCave 10 years ago

First of all: Hi.

Since the last developer forum I was active in has been bought and pulverized by some people I've never entered a forum again for a while.

Now a year later I am confident again and hope to have found a new forum right here for now and the future.

My problem:

> The basic architecture

1. I'm working on a Android game project using multithreading.

2. The game has several game loops i.e. a "logic loop"

3. Every loop has it's own "unit" memory to iterate through

> The problem

When creating a new "unit" while the game is running (i.e. a tank was produced in a factory -> this example happens in the logic-thread/loop) I need to make the reference of the tank known to the other threads by saving the reference in their "unit memory" (a list or a set).

Of course this would terminate the program with an error, since you can't modify a list while at the same time iterating over it.

My first solution was to synchronize the lists and make them thread safe. This however leads to the problem that it makes first of all the whole code significantly a lot slower and the thread adding the new objects had to wait for every thread to finish iterating causing the whole game to stuck a few ms when a new unit was created.

Has anyone an idea how I could possibly solve this multithreading issue?

Thank you very much

- Icca

Advertisement

You could add a queue to the thread such that you don't need to synchronize any of the core elements. http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html then you just need to see if anything new has arrived, and then add it to your list from the thread owning the list.

You could use a ConcurrentLinkedQueue as your list, and iterate using the iterator method. Then elements are added to directly to the thread's list, but it uses a wait-free algorithm instead of locking the whole list. You can alternatively use CopyOnWriteArrayList if adding elements is very rare.

Hi! Hope you will like it here. smile.png

Does each thread need its own entity list in memory?

Can't one thread actually manage the modifiable scene graph / entity list ... and pass an immutable frameEntityList, built specifically for the next frame, to the other threads?

Guess the logic thread would have to remember or signal that a tank was built, the entity management would create the actual object for the next frame and add it to the immutable list.

You might even be able to add some culling when you build the frameEntityList.

Disclaimer: as far as I know such a central thread managing logic is not uncommon, but I am not yet a concurrency expert.

Given enough eyeballs, all mysteries are shallow.

MeAndVR

A central thead managing logic is surely common, but it's inherrently less parellel than distrubuting the logic to different threads. If the logic can be distributed, you should do so as much as possible. There's not enough information in this thead to say if it can work in this case. It mostly depends on how much logic there is, and how often you need interthread comunication, in this case in the form of new objects created.

Either mine or VildNinja's solutions will reduce the cost of that interthread comunication, especially for the case that there is no comunication. But if you have too many objects being shared like that, or if there isn't enough logic to make up for the fact that it all needs to be synced when rendering, splitting the logic may not be worthwile.

You could use a ConcurrentLinkedQueue as your list, and iterate using the iterator method. Then elements are added to directly to the thread's list, but it uses a wait-free algorithm instead of locking the whole list. You can alternatively use CopyOnWriteArrayList if adding elements is very rare.

and @VildNinja

I have played around with this idea to use an "object stream". I was not aware of ConcurrentLinkedQueue which is a very interesting class in that case.

I've tried it also with a concurrent HashSet by using


Set set = Collections.newSetFromMap( new ConcurrentHashMap() );

to increase performance furthermore but I like the FIFO-Version which can become handy and looks also better in code.

Maybe will change it later at the very end of development to (Concurrent)HashSet to potentially increase performance.

An example abstract class showing the general architecture of one of my unit memory classes implementing the idea with a ConcurrentLinkedQueue.


public class ThreadUnitMemory< A extends AbstractObject<A>> {
	private final HashSet<A>				allObjects;
	private final ConcurrentLinkedQueue<A>	clqObjectStreamNew, clqObjectStreamKill;
	
	public LoopDatabase() {
		allObjects = new HashSet<A>();
		clqObjectStreamNew = new ConcurrentLinkedQueue<A>();
		clqObjectStreamKill = new ConcurrentLinkedQueue<A>();
	}
	
	public void addObjectToThread( A a ) {
		clqObjectStreamNew.offer( a );
	}
	
	public void removeObjectFromThread( A ao ) {
		clqObjectStreamTrash.offer( a );
	}

	private A buffer;
	
	public void loop() {
		while( !clqObjectStreamNew.isEmpty() ) {
			buffer = clqObjectStreamNew.poll();
			allObjects.add( buffer );
		}
		
		while( !clqObjectStreamTrash.isEmpty() ) {
			buffer = clqObjectStreamTrash.poll();
			allObjects.remove( buffer );
		}

		// compute all the logic stuff we are actually here for - iterating over allObjects
	}
}

Hi! Hope you will like it here. smile.png

Does each thread need its own entity list in memory?

[...]

An indeed interesting architectural solution I would really like to implement but I've decided against but will try that out someday definitly for other projects.

Reasons I decided against:

>> Needs more time to implement. Especially when you are later in development stage, I guess it would be best to implement this from the very beginning.

>> Needs lots of ressources in general which is not justified in my case. The threads are totally seperated from one another beside the little tweak that new objects have to be added to their memory when needed.

>> All threads have their individual memory architecture.

the logic-thread for example only needs a simple set of objects;

the OpenGL-thread is sorting the objects in a scene graph;

the AI-thread is sorting with different hyrachies depending on the ai's and their relation to the object;

and this goes on... again it was designed from the beginning that every thread is and works totally independent.

However, I've wrote this down for a later project.

Thank all of you very much!

- Ica

This topic is closed to new replies.

Advertisement