Concurrency Control

Hey there,

We’re developing a game that deals with a lot of entities (enemies) and the killing of them. Something like a tower defense game. We’re having serious issues with concurrency. For instance, there’s a function “A” that iterates over a table of enemies for dealing damage to them, but at any time in the game, an enemy might be killed by any other source of damage and be removed from the enemies table. If this happens concurrently, function A will get to an enemy that doesn’t exist anymore and start spilling out ‘nil’ errors.

I’m not asking for a work around for this as I’m able to find one myself but the thing is that it will never really fix the problem, just make it less frequent.

I would like to know if there is any support for concurrency control in Lua/Corona, so I can actually make sure this doesn’t happen.

Thanks in advance,

Manuel Costa
CluelessIdeas [import]uid: 61899 topic_id: 11774 reply_id: 311774[/import]

This sounds like an application problem, not a Corona problem.

[import]uid: 58455 topic_id: 11774 reply_id: 42839[/import]

At the start of the function, you should wrap the following if/then statement to check for the object’s validity.

[lua]function enemyControl()
if enemy and enemy.removeSelf then
– do your stuff here
end
end[/lua]

That way, if it happens to get destroyed just as it’s about to launch the function, which I might assume would be on a timer, then it will exit out of the function with no error.

[import]uid: 6084 topic_id: 11774 reply_id: 42858[/import]

That’s basically what I’ve been doing, every time I’m about to deal with such entity I check if it still exists.

The problem is if that removal occurs within that if statement! It passes the check, since the object still exists but then the function is stopped, CPU time is allocated to another thread or something which is running the timers, the object is deleted and then the previous function is resumed somewhere inside that if, but now the enemy doesn’t exist anymore. It’s a concurrency problem.

One way to deal with this is to obtain mutual exclusion, with the use of monitors, semaphores or locks for example.

What I need is a way to lock the access to the enemies variable so that only one piece of code deals with it at a time. Or signal that a piece of code should be treated as atomic (like a transaction in database systems), and never be interrupted during it’s execution. [import]uid: 61899 topic_id: 11774 reply_id: 42871[/import]

I would suggest this workaround:

Assuming the variable is called enemy

  1. When creating the enemy, create a variable within it called enemy.destroyMe and set it to false.
  2. Instead of destroying the enemy in another function, simply change the value of that enemy’s enemy.destroyMe variable to true, then add the score, disable any further physics collision, and/or even set the alpha to 0 to make it disappear.
  3. By the time “function A” decides to run, the variable and object will still be there, and within that function, test for enemy.destroyMe and destroy itself if necessary.

Just takes some thinking outside the box, but I think that will be a better way to handle it, and the object itself is doing its own cleanup. [import]uid: 6084 topic_id: 11774 reply_id: 42876[/import]

As I said before, I’m not looking for a workaround. I thank you a lot for your very valuable effort. Those are both suggestions that reduce a lot the chance of this happening but it doesn’t fix it completely.

The thing is that “another function” might be “A” itself. So if at any time A removes the element, then another instance of A might find itself without the element it was expecting to be there.

There is no way to deal with this problem at language level as I said, it’s not a matter of thinking out of the box.

What I want is to know if there is any way to deal with this in Lua/Corona, as there is in some other languages like Java, C#, etc.

Java: http://www.artima.com/insidejvm/ed2/threadsynch.html
C#: http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx [import]uid: 61899 topic_id: 11774 reply_id: 42886[/import]

What does your game loop look like at a high level? How is it that multiple threads have access to global data?

Sorry…new to Corona. My only other graphics experience was with single-threaded OpenGL applications. [import]uid: 58455 topic_id: 11774 reply_id: 42891[/import]

Much of what happens in Corona is actually single threaded. Locks might not actually help you here.

I think the ‘problem’ you are experiencing is that Corona allows underlying C objects to be destroyed independently of their Lua userdata object. In more conventional Lua, entire objects don’t get destroyed until they have no more references and the garbage collector collects them. But Corona made the decision to allow objects to be cleaned up separately from their Lua lifecycle which reduces the need to wait for the garbage collector to free memory, but may introduce this dangling reference problem you are experiencing.

Instead, maybe a better approach is to use Lua weak (table) references. The table you are traversing through that holds the list of objects might be better off as a weak table. Then assuming nothing else is holding a strong reference to the object when it is destroyed, it will automatically be deleted from your table and you will avoid this case entirely.
[import]uid: 7563 topic_id: 11774 reply_id: 42909[/import]

Well, that makes a lot of sense. I was completely convinced it was concurrency playing tricks on me. Thanks a lot for the info, I’ll try that and see what happens.

You say that corona is mainly single threaded, which makes me suppose it’s not completely. Is there anything we should take care, or that small multithreading won’t ever hurt us developers? If yes, can you answer my question of how to deal with it? [import]uid: 61899 topic_id: 11774 reply_id: 42929[/import]

Some concurrency is created by us, some is created by the underlying operating system. But these are implementation details that you are not supposed to care about if everybody did their job right.

Now if there are bugs, you need to report them. Sometimes there is a workaround, sometimes not.

For example, Apple implements some of their OpenAL in a background thread. There are some known race condition bugs in Apple’s system. Unfortunately, we can’t really work around them and have to wait for them to fix them. (Many have been fixed, but you need the latest iOS version.)

[import]uid: 7563 topic_id: 11774 reply_id: 42937[/import]

One more thing, I think there is a rule about not removing objects in the middle of Box2D collision handlers. [import]uid: 7563 topic_id: 11774 reply_id: 42938[/import]