lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


* steve donovan:

> I'm trying to understand the problem here. Presumably the destructors
> are called in the current state, and execution pauses until they are
> finished.  What 'gotcha' can burn us here?

Suppose you want to put an object in a global array when it is
created, and remove it when it is destructed.  Something like this:

    local state = {}
    function create()
        local t = {}
        state[#state + 1] = t
        return t
    end
    
    function destroy(t)
        for i = #state, 1, -1 do
            if state[i] == t then
                table.remove(t, i)
                break
            end 
        end
    end

(The advantage over weak tables is that the state table is more
up-to-date if destroy() is called on all relevant scope exists.
But the similarity to weak tables is not an accident, finalizers
allow you to create weak data structures, and weak data structures
with queues allow you to implement finalizers.)

However, that code is not correct because

  state[#state + 1] = t

is a table write.  Table writes can trigger table resize, which in
turn can trigger garbage collection, which can run a destroy()
function.  After that, #state has changed, so you write to the wrong
table slot.  Similary, destroy() may store non-nil values, so it may
trigger garbage collection, too, and run even concurrently with
itself.

Of course, this is just a toy example.  But I fear that it's
impossible to write correct finalizers in Lua without some concurrency
primitives.

> Another approach is that the core creates a coroutine which is called
> when any user-finalization has to happen. This is generally considered
> OK in other contexts, e.g. event-driven callbacks.

This would provide serialization, but it's tricky to implement because
you need to put the object pending finalization on some queue.
Otherwise you're hosed when another object needs to be finalized while
the finalization coroutine is already running.

> In other words, is there not a safe way to run finalizers without the
> full pre-emptive mechanism found in C# or Java?

If you have got an event loop, you can run them from the event loop
with very little risk.