[Resolved] How can i implement a lock/semaphore

I was wondering on how I could go about implementing a lock, or if there’s any support for atomic operations as I want to avoid certain race conditions in my code, which have to do with removing a display object.
[import]uid: 121569 topic_id: 32304 reply_id: 332304[/import]

@alexgloushenkov

It sounds like you may have some kind of producer-consumer scenario where you want to ensure mutual exclusion? Am I right?

Corona doesn’t (AFAIK) support any kind of mutual-exclusion features, but you might be able to implement something in software: http://en.wikipedia.org/wiki/Mutual_exclusion#Software_solutions

Can you please elaborate on the specific problem you are trying to solve or avoid? I may be able to make a suggestion.

@alexgloushenkov

As far as being safe with regards to display object removal, you could always do this:

  1. Add this code in main.cs or wherever you want.[code]

function _G.isDisplayObject( obj )
if( obj and obj._class and obj._proxy) then return true end
return false
end
[/code]

  1. Use the function wherever you are worried about accessing a deleted display object: if( not isDisplayObject( obj ) ) then return end -- obj is a handle to the possibly removed display object.

Note: This solution is not perfect but it will work in all cases with display objects where removeSelf() may have been called.
I know some folks reading this may be wondering why this even matters. Let me explain with an example:

local myObj = display.newRect( 0,0, 100, 100)  
myObj.x = 10  
myObj.y = 10  
  
-- function to move 'myObj' to the right by 10 pixels  
local closure = function()   
 myObj.x = myObj.x + 10  
end  
  
timer.performWithDelay( 500, closure )  
  
myObj:removeSelf()  

In the above code, the closure will be executed 1/2 second after ‘myObj’ is removed and the game will crash or something bad.

There are two ways to fix this.

Fix #1 - Auto-cancel

local myObj = display.newRect( 0,0, 100, 100)  
myObj.x = 10  
myObj.y = 10  
  
-- function to move 'myObj' to the right by 10 pixels  
myObj.timer = function( self )   
 myObj.x = myObj.x + 10  
end  
  
timer.performWithDelay( 500, myObj )  
  
myObj:removeSelf()  

Now, when ‘myObj’ is removed, the scheduled call (by timer) is automatically cancelled. This may seem great, but what happens if you need two different scheduled functions to access ‘myObj’. Answer: Try fix #2.

Fix #2 - Check for valid object

function \_G.isDisplayObject( obj )  
 if( obj and obj.\_class and obj.\_proxy) then return true end  
 return false  
end  
  
local myObj = display.newRect( 0,0, 100, 100)  
myObj.x = 10  
myObj.y = 10  
  
-- function to move 'myObj' to the right by 10 pixels  
local closure = function()   
 if not isDisplayObject( myObj ) then return end  
 myObj.x = myObj.x + 10  
end  
timer.performWithDelay( 500, closure )  
  
-- function to move 'myObj' to the down by 10 pixels  
local closure2 = function()   
 if not isDisplayObject( myObj ) then return end  
 myObj.y = myObj.y + 10  
end  
timer.performWithDelay( 500, closure2 )  
  
myObj:removeSelf()  

In the above case, the display object is removed and replaced (by Corona) with a simple table. Because the table does not have both _class and _proxy fields, the function isDisplayObject() detects this as not being a display object and returns false. Problem fixed.

-Ed
[import]uid: 110228 topic_id: 32304 reply_id: 128543[/import]

Or KISS…

if obj and type(obj.removeSelf) == "function" then  
 obj:removeSelf()  
 obj = nil  
end  

[import]uid: 19626 topic_id: 32304 reply_id: 128545[/import]

@robmiracle

I’m sure you’re not calling me stupid. :frowning: ) (KISS == Keep It Simple Stupid).

:wink:

You are however absolutely right. I didn’t consider that alexgloushenkov may simply have been dealing with a problem of a nil handle.

I really am joking here by the way (about the KISS part).

I’m sure my answer seems over-kill, but I blame it on my day. I’ve been working like a fiend writing docs and tutorials today. I guess I was still in-the-zone when I answered.

Cheers,

Ed

PS - I like this part (smacks forehead) type(obj.removeSelf) == "function"
I think I’ll snag that. Thanks!
[import]uid: 110228 topic_id: 32304 reply_id: 128548[/import]

(edit, didnt get quoted)
if obj and type(obj.removeSelf) == “function” then
obj:removeSelf()
obj = nil
end

Nah this is what I currently have, and I basically can happen upon cases where multiple objects try both do that to remove a display object, and if it’s possible that both object A and object B both pass the conditional and one of them removes the object, while the other one tries to remove it also but it’s already gone (already passed the if statement before it was removed) [import]uid: 121569 topic_id: 32304 reply_id: 128550[/import]

I don’t believe in calling anyone stupid (save some people in the political party that I don’t’ support.), so translate KISS to “Keep It Simple Silly”…

But yea, that’s the point. While my code doesn’t quite do what semaphores and locks do, it does protect against your app crashing if you try to remove something that doesn’t exist.
[import]uid: 19626 topic_id: 32304 reply_id: 128623[/import]

if obj and type(obj.removeSelf) == “function” then
obj:removeSelf()
obj = nil
end

Just to reiterate, this is the code that I currently have that can crash sometimes, and what I basically need is for this block of code to be able to execute as an atomic statement, since for me it works fine in the general case, but sometimes there are race conditions which cause this code to break (i.e. two functions both try executing this block, one function passes the IF, second function passes the IF, first function removes the object, second function tries to remove the object but crashes

[import]uid: 121569 topic_id: 32304 reply_id: 128628[/import]

Corona’s LUA environment is not multi-threaded, and so you could consider all operations to be linear and atomic. There can be no race conditions either, since it all runs linearly.

Some important things to remember is that obj = nil, will only remove the reference in that specific scope. i.e. in this code:

local grp = display.newGroup  
  
local function destroy(obj)  
 obj:removeSelf()  
 obj = nil  
end  
  
destroy(grp)  

grp is not nilled out, and only the local reference obj is nil. You may also need to verify that removeSelf() will clear the removeSelf function out of the object’s table. One possible trick could be to manually remove that function in your Destroy, or if you want to get tricky, replace it with a blank function.

local function destroy(obj)  
 obj:removeSelf()  
 obj.removeSelf = nil --This allows your previous check to catch a destroyed object in a more reliable fashion  
 obj.removeSelf = function() end --This means all subsequent calls to removeSelf do nothing, but at least they won't break  
end  

The second one is easier to manage, but it also could mean you may not know when you are holding onto dead references (and wasting memory as a result). A second trick to catch dead references is to replace the empty function with simple logger that reports a callstack, and the fact that an object was trying to be removed twice. [import]uid: 134101 topic_id: 32304 reply_id: 128638[/import]

local grp = display.newGroup

local function destroy(obj)
obj:removeSelf()
obj = nil
end
destroy(grp)

In such an example, how could I go about setting grp to nil inside of that destroy function instead of just the local reference to it from the function? [import]uid: 121569 topic_id: 32304 reply_id: 128642[/import]

You can’t and you don’t. Not sure if you are used to C++, but it’d be like trying to redirect all pointers to an object to point somewhere else. The amount of extra processing and memory that would be required for each reference to each object to know about all others is just not worth it.

EDIT: In LUA, you still can solve your question, by accessing grp(an upvalue in LUA), instead of obj, but that merely fixes the example, but not actually a valid solution to cleaning up lingering references.

Often times, you simply use a system on the object to get it’s state.
For Example:

function \_G.destroyDisplayObject(obj)  
 if obj and obj.removeSelf and not obj.destroyed then --destroyed boolean lets you check if an object is destroyed  
 obj:removeSelf()  
 obj.destroyed = true  
 end  
end  

This way, you can use obj.destroyed to detect if the object is destroyed or not(so long as you use this destroy function and not removeSelf directly). Other options include keeping a table of active references (cleaning the out on destruction), replacing the removeSelf function to something else on destruction(as above), or having a main reference that gets destroyed, and using weak references and get accessors so you can detect if they are cleaned up at any time(potentially unsafe since a removeSelf, and garbage collect occur at different times). [import]uid: 134101 topic_id: 32304 reply_id: 128643[/import]

@alexgloushenkov

It sounds like you may have some kind of producer-consumer scenario where you want to ensure mutual exclusion? Am I right?

Corona doesn’t (AFAIK) support any kind of mutual-exclusion features, but you might be able to implement something in software: http://en.wikipedia.org/wiki/Mutual_exclusion#Software_solutions

Can you please elaborate on the specific problem you are trying to solve or avoid? I may be able to make a suggestion.

@alexgloushenkov

As far as being safe with regards to display object removal, you could always do this:

  1. Add this code in main.cs or wherever you want.[code]

function _G.isDisplayObject( obj )
if( obj and obj._class and obj._proxy) then return true end
return false
end
[/code]

  1. Use the function wherever you are worried about accessing a deleted display object: if( not isDisplayObject( obj ) ) then return end -- obj is a handle to the possibly removed display object.

Note: This solution is not perfect but it will work in all cases with display objects where removeSelf() may have been called.
I know some folks reading this may be wondering why this even matters. Let me explain with an example:

local myObj = display.newRect( 0,0, 100, 100)  
myObj.x = 10  
myObj.y = 10  
  
-- function to move 'myObj' to the right by 10 pixels  
local closure = function()   
 myObj.x = myObj.x + 10  
end  
  
timer.performWithDelay( 500, closure )  
  
myObj:removeSelf()  

In the above code, the closure will be executed 1/2 second after ‘myObj’ is removed and the game will crash or something bad.

There are two ways to fix this.

Fix #1 - Auto-cancel

local myObj = display.newRect( 0,0, 100, 100)  
myObj.x = 10  
myObj.y = 10  
  
-- function to move 'myObj' to the right by 10 pixels  
myObj.timer = function( self )   
 myObj.x = myObj.x + 10  
end  
  
timer.performWithDelay( 500, myObj )  
  
myObj:removeSelf()  

Now, when ‘myObj’ is removed, the scheduled call (by timer) is automatically cancelled. This may seem great, but what happens if you need two different scheduled functions to access ‘myObj’. Answer: Try fix #2.

Fix #2 - Check for valid object

function \_G.isDisplayObject( obj )  
 if( obj and obj.\_class and obj.\_proxy) then return true end  
 return false  
end  
  
local myObj = display.newRect( 0,0, 100, 100)  
myObj.x = 10  
myObj.y = 10  
  
-- function to move 'myObj' to the right by 10 pixels  
local closure = function()   
 if not isDisplayObject( myObj ) then return end  
 myObj.x = myObj.x + 10  
end  
timer.performWithDelay( 500, closure )  
  
-- function to move 'myObj' to the down by 10 pixels  
local closure2 = function()   
 if not isDisplayObject( myObj ) then return end  
 myObj.y = myObj.y + 10  
end  
timer.performWithDelay( 500, closure2 )  
  
myObj:removeSelf()  

In the above case, the display object is removed and replaced (by Corona) with a simple table. Because the table does not have both _class and _proxy fields, the function isDisplayObject() detects this as not being a display object and returns false. Problem fixed.

-Ed
[import]uid: 110228 topic_id: 32304 reply_id: 128543[/import]

Or KISS…

if obj and type(obj.removeSelf) == "function" then  
 obj:removeSelf()  
 obj = nil  
end  

[import]uid: 19626 topic_id: 32304 reply_id: 128545[/import]

@robmiracle

I’m sure you’re not calling me stupid. :frowning: ) (KISS == Keep It Simple Stupid).

:wink:

You are however absolutely right. I didn’t consider that alexgloushenkov may simply have been dealing with a problem of a nil handle.

I really am joking here by the way (about the KISS part).

I’m sure my answer seems over-kill, but I blame it on my day. I’ve been working like a fiend writing docs and tutorials today. I guess I was still in-the-zone when I answered.

Cheers,

Ed

PS - I like this part (smacks forehead) type(obj.removeSelf) == "function"
I think I’ll snag that. Thanks!
[import]uid: 110228 topic_id: 32304 reply_id: 128548[/import]

(edit, didnt get quoted)
if obj and type(obj.removeSelf) == “function” then
obj:removeSelf()
obj = nil
end

Nah this is what I currently have, and I basically can happen upon cases where multiple objects try both do that to remove a display object, and if it’s possible that both object A and object B both pass the conditional and one of them removes the object, while the other one tries to remove it also but it’s already gone (already passed the if statement before it was removed) [import]uid: 121569 topic_id: 32304 reply_id: 128550[/import]

Well thanks a ton Ntero,

I didn’t know that setting that reference to nil didn’t nil out the actual object, and after I accounted for that all of my problems went away

[import]uid: 121569 topic_id: 32304 reply_id: 128655[/import]

I don’t believe in calling anyone stupid (save some people in the political party that I don’t’ support.), so translate KISS to “Keep It Simple Silly”…

But yea, that’s the point. While my code doesn’t quite do what semaphores and locks do, it does protect against your app crashing if you try to remove something that doesn’t exist.
[import]uid: 19626 topic_id: 32304 reply_id: 128623[/import]

if obj and type(obj.removeSelf) == “function” then
obj:removeSelf()
obj = nil
end

Just to reiterate, this is the code that I currently have that can crash sometimes, and what I basically need is for this block of code to be able to execute as an atomic statement, since for me it works fine in the general case, but sometimes there are race conditions which cause this code to break (i.e. two functions both try executing this block, one function passes the IF, second function passes the IF, first function removes the object, second function tries to remove the object but crashes

[import]uid: 121569 topic_id: 32304 reply_id: 128628[/import]

Corona’s LUA environment is not multi-threaded, and so you could consider all operations to be linear and atomic. There can be no race conditions either, since it all runs linearly.

Some important things to remember is that obj = nil, will only remove the reference in that specific scope. i.e. in this code:

local grp = display.newGroup  
  
local function destroy(obj)  
 obj:removeSelf()  
 obj = nil  
end  
  
destroy(grp)  

grp is not nilled out, and only the local reference obj is nil. You may also need to verify that removeSelf() will clear the removeSelf function out of the object’s table. One possible trick could be to manually remove that function in your Destroy, or if you want to get tricky, replace it with a blank function.

local function destroy(obj)  
 obj:removeSelf()  
 obj.removeSelf = nil --This allows your previous check to catch a destroyed object in a more reliable fashion  
 obj.removeSelf = function() end --This means all subsequent calls to removeSelf do nothing, but at least they won't break  
end  

The second one is easier to manage, but it also could mean you may not know when you are holding onto dead references (and wasting memory as a result). A second trick to catch dead references is to replace the empty function with simple logger that reports a callstack, and the fact that an object was trying to be removed twice. [import]uid: 134101 topic_id: 32304 reply_id: 128638[/import]