Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Why is my coroutine yielding the thread?

Asked by
RafDev 109
8 years ago

According to my knowledge on coroutines- which may be wrong -, threads created by coroutine.wrap are executed somewhere else, not yielding the current thread.

However, when I run a coroutine that delays itself, it still is yielding the current thread.

Am I doing something wrong? Is that how it's supposed to work?

My code is below:

local CustomDelay = coroutine.wrap(function(tim,f)

tim = tonumber(tim)

if type(f)~='function' then f = function() end end

if not tim then tim=0 end

local supposedtime = os.time()+tim

local function uselessfunction()
    -- Do nothing
end
print('Delaying function "' .. (function() local str = tostring(f);
if not str then str = 'function: UnknownHexAddress' end str=str:sub(10) return str
end)() .. '" (' .. tostring(tim) .. ') seconds.')
repeat uselessfunction() until os.time()>=supposedtime -- Alternative to wait()
local s,e = pcall(f)
if not s then warn('Error while delaying function: ' .. e) end
return s,e

end)

CustomDelay(3,function() print"Woo!" end)) -- Delays the function 3 seconds, supposedly not affecting the current thread

warn("This should come before the 'Woo!', since it is not delayed")

PS.: I know I wouldn't be able to use coroutine.wrap like that, since if I ran CustomDelay again it'd error that CustomDelay was dead - I was just using it for the example.

1 answer

Log in to vote
0
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
8 years ago

Lua is not multithreaded -- all coroutines run on the same thread. Thus busy-waiting loops like you've written block everything until it's done.


A coroutine describes the place it's executing at (and all the local variables). resume and yield switches between which coroutine is being actively used by the interpreter. But this is a switch -- only one can be active at a time.

Due to careful scheduling, it looks like many coroutines are happening at the same time. What is actually happening is that things like wait make the current coroutine yield; after the current ROBLOX-managed-coroutine yields, ROBLOX looks for the next coroutine that needs to be started (e.g., because an event fired, or because the duration of a wait ended), and resumes that one.


I highly recommend not putting more than one statement on a line, and putting spaces around operators (e.g., + or =).

You can do some code cleanup in your script.

  1. if not tim then tim=0 end can be replaced with tim = tim or 0.
  2. This can be combined with the previous to just make tim = tonumber(tim) or 0, though I'm not really sure why you want to accept non-numbers as the first parameter.
  3. It makes even less sense to coerce f to a function if it's not.
  4. Don't define your function inside the print! That's completely unreadable and unnecessary.
  5. Same trick can be applied to str. Except that tostring can't return nil, so that shouldn't happen.

At this point you have something like this:

local function doNothing()
    -- Do nothing
end

local CustomDelay = coroutine.wrap(function(tim,f)
    tim = tonumber(tim) or 0

    assert(type(f) == "function")

    local supposedtime = os.time() + tim

    local function functionHex()
        return tostring(f):sub(10)
    end
    print('Delaying function "' .. functionHex() .. '" (' .. tostring(tim) .. ') seconds.')
    repeat
        doNothing()
    until os.time() >= supposedtime -- Alternative to wait()
    local s,e = pcall(f)
    if not s then
        warn('Error while delaying function: ' .. e)
    end
    return s,e
end)

CustomDelay(3,function()
    print("Woo!")
end)

    -- Delays the function 3 seconds, supposedly not affecting the current thread

warn("This should come before the 'Woo!', since it is not delayed")
  1. functionHex really doesn't need to pull the local f out. You should just make it an argument and move it outside of CustomDelay.

The result is much cleaner:

local function doNothing()
    -- Do nothing
end

local function functionHex(f)
    return tostring(f):sub(10)
end

local CustomDelay = coroutine.wrap(function(tim,f)
    tim = tonumber(tim) or 0

    assert(type(f) == "function")

    local supposedtime = os.time() + tim

    print('Delaying function "' .. functionHex(f) .. '" (' .. tostring(tim) .. ') seconds.')
    repeat
        doNothing()
    until os.time() >= supposedtime -- Alternative to wait()
    local s, e = pcall(f)
    if not s then
        warn('Error while delaying function: ' .. e)
    end
    return s, e
end)

CustomDelay(3,function()
    print("Woo!")
end)

    -- Delays the function 3 seconds, supposedly not affecting the current thread

warn("This should come before the 'Woo!', since it is not delayed")

0
Alright, thanks! I didn't know much about coroutines, and really didn't care about cleaning my code, but perhaps I should start doing so. RafDev 109 — 8y
Ad

Answer this question