Coroutine while loop behaving weirdly

  1. What do you want to achieve?
    I want to make a lightbar / siren system for my emergency vehicles.

  2. What is the issue?
    When I start the ELS loop, everything prints as intended except “Loop # end”. That means something is yielding inside the loop. The value is also not set, the toggle functions are not in order in the while loop (?).

  3. What solutions have you tried so far?
    I’ve asked on some support channels and asked ChatGPT.

Coroutine function
local function startLightLoop()
	print("Starting...")
	if lightLoopCoroutine then
		print("Already started, returning")
		return
	end
	local waitTime = 0.03
	print("Creating coroutine...")
	lightLoopCoroutine = coroutine.create(function()
		print("Starting loop!")
		while true do
			print("Loop # start")
			task.spawn(function()
				toggleFront(true)
				task.wait(0.2)
				toggleFront(false)
			end)
			
			toggleRed(true)
			task.wait(waitTime)
			toggleRed(false)
			task.wait(waitTime)
			toggleRed(true)
			task.wait(waitTime)
			toggleRed(false)
			task.wait(waitTime)
			toggleBlue(true)
			task.wait(waitTime)
			toggleBlue(false)
			task.wait(waitTime)
			toggleBlue(true)
			task.wait(waitTime)
			toggleBlue(false)
			task.wait(0.3)
			print("Loop # end")
		end
	end)
	print("Setting value...")
	values.On.Value = true
	print("Starting coroutine...")
	local success, err = coroutine.resume(lightLoopCoroutine)
	if not success then
		warn("Error while starting light loop coroutine:", err)
		return
	end
	warn("Finished!")
end
Output
 16:18:06.158  Turning on  -  Server - SirenControlServer:189
 16:18:06.159  Starting...  -  Server - SirenControlServer:89
 16:18:06.159  Creating coroutine...  -  Server - SirenControlServer:95
 16:18:06.159  Setting value...  -  Server - SirenControlServer:125
 16:18:06.159  Starting coroutine...  -  Server - SirenControlServer:127
 16:18:06.159  Starting loop!  -  Server - SirenControlServer:97
 16:18:06.159  Loop # start  -  Server - SirenControlServer:99
 16:18:06.159  (toggling front: true)  -  Server - SirenControlServer:56
 16:18:06.160  (toggling red: true)  -  Server - SirenControlServer:32
 16:18:06.160  Finished!  -  Server - SirenControlServer:133
 16:18:06.160  (toggling red: false)  -  Server - SirenControlServer:32
 16:18:06.160  (toggling blue: false)  -  Server - SirenControlServer:44
 16:18:06.160  (toggling front: false)  -  Server - SirenControlServer:56
 16:18:06.160  (toggling red: false)  -  Server - SirenControlServer:32
 16:18:06.161  (toggling blue: false)  -  Server - SirenControlServer:44
 16:18:06.161   ▶ (toggling front: false) (x2)  -  Server - SirenControlServer:56
Toggle functions

All toggle functions are the same except some values are changed.

local function toggleBlue(newValue: boolean)
	print("(toggling blue: "..tostring(newValue)..")")
	local newTransparency = newValue and 0 or 1
	local blueLights = lights.Lightbar.LeftBlue
	for _, light in blueLights:GetChildren() do
		if not isLight(light) then
			continue
		end
		light.Transparency = newTransparency
	end
end

Thanks for any help!

I wasn’t able to reproduce this issue in my own testing. How is this function being called? Is there a stop function that might be affecting things? Are you resuming the thread anywhere else?

Try replacing

lightLoopCoroutine = coroutine.create(function()
    -- [...]
end)

with

task.spawn(function()
    -- [...]
end)

(And removing the coroutine.resume()). I typically avoid using the coroutine library in favor of the task library (other than the functions that don’t have an equivalent like coroutine.running()), as the coroutine library is a lua thing, and not always quite well integrated with the roblox apis (resuming a yielded callback function with the coroutine library breaks it, …)

Moreover, coroutine.resume() is odd in the sense that it also acts like a pcall. You are properly checking for errors though, so that’s good. But I am not sure what happens if an error happens, inside the coroutine.create(), but after a task.wait(). The task.wait() is responsible for yielding the coroutine, and resuming it again afterwards, but does it still keep that behaviour of suppressing errors? This is something I would have to test


I tested it, and errors appear in the output as normal, after a task.wait()

  • The function is being called from a RemoteEvent connection that handles the requests from the client to change the ELS.
  • In the same connection it checks if the ELS is on; if it’s on it turns it off (-> closes the coroutine) and vice versa.
  • This is the only place I resume the thread is from here. I have an other function to close this thread.

How would I close the thread if I use task.spawn()?

What do you mean?

task.spawn() here would act basically the same as your coroutine implementation (although you would call task.spawn() where you currently call coroutine.resume()

The thread is closed when it reaches the end, or if you use task.cancel() on the thread (task.spawn() returns the thread, or you can call coroutine.running() to get the running thread). I don’t see any coroutine.close() in your code, so I don’t see why you would need to use task.cancel()

1 Like

I have an other function doing coroutine.close() and that stops the ELS (the loop). When the user presses a GUI button, the client sends a request to the RemoteEvent that closes the thread.

The thread wouldn’t reach its end because it’s a while loop.

Alright, I’ll try that when I’m home.

1 Like

I just tested it and nothing has changed.

I’ve replaced

coroutine.resume(lightLoopCoroutine)

with

task.spawn(lightLoopCoroutine)

I have a honest question (no offense): is this a ragebait? Nah like an actual question

--!strict
local lightLoopCoroutine:thread? = nil
local On = values.On
local function Loop():()
	print("Starting loop!")
	local waitTime = 0.03
	while true do
		print("Loop # start")
		toggleFront(true)
		task.delay(0.2,toggleFront,false)

		toggleRed(true)
		task.wait(waitTime)
		toggleRed(false)
		task.wait(waitTime)
		toggleRed(true)
		task.wait(waitTime)
		toggleRed(false)
		task.wait(waitTime)
		toggleBlue(true)
		task.wait(waitTime)
		toggleBlue(false)
		task.wait(waitTime)
		toggleBlue(true)
		task.wait(waitTime)
		toggleBlue(false)
		task.wait(0.3)
		print("Loop # end")
	end
end

local function startLightLoop()
	print("Starting...")
	if lightLoopCoroutine then
		print("Already started, returning")
		return
	end
	local waitTime = 0.03
	print("Creating coroutine...")
	lightLoopCoroutine = coroutine.create(Loop)
	print("Setting value...")
	On.Value = true
	print("Starting coroutine...")
	coroutine.resume((lightLoopCoroutine::any)::thread)
	
	warn("Finished!")
end
2 Likes

Thanks for all the help but the problem wasn’t with the loop. Sorry for wasting your time.

Basically the problem was that I stopped the light loop right after I started it. (I disabled an other light mode after I enabled this one, and disabling the other one would maunally disable all lights and disabling all the lights stopped the loop :sweat_smile:)

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.