Skip to main content

Thread

Threads utilize the coroutines of the underlying script VM and are designed to execute loops or delays without blocking the game. A thread exists until its code has finished executing or it is manually terminated using Kill.

info

All threads run sequentially (synchronously) on the main thread. Therefore, there is no need to worry about writing thread-safe code.

warning

If you use an infinite loop inside a thread, you must call Thread.Pause() (even Thread.Pause(0) is sufficient). Failing to do so will freeze the entire game or server, as the thread will never yield control back to the main thread.

Quick Reference

NameTypeDescription
CreateSharedCreates a new thread with a function that is executed asynchronously.
PauseSharedPauses the current thread for the specified duration.
KillSharedKills the specified thread on the next script tick.
IsAliveSharedReturns whether the specified thread is currently alive and running.

Timing

Threads are driven by the script tick. A thread never runs between two ticks, and everything below follows from that:

  • The server ticks about every 10 ms, plus however long the tick itself takes.
  • The client ticks once per rendered frame: roughly 16 ms at 60 FPS, 33 ms at 30 FPS, and much longer while the game stutters or streams.

Thread.Pause(ms) therefore means at least ms, never exactly ms. The thread wakes up on the first tick after the time has elapsed, so a pause is always rounded up to the next tick.

danger

Do not use Thread.Pause to measure time. Adding up the values you passed to it does not give you elapsed milliseconds, because the error accumulates with every iteration and is different on every machine. Thread.Pause(1) in a loop is not a millisecond counter: on the server it advances in steps of roughly 10 ms, on the client in frames.

To measure time, read a clock instead:

Thread.Create(function()
-- Client: milliseconds since the game started.
local start = Game.GetGameTimer()

while Game.GetGameTimer() - start < 5000 do
Thread.Pause(0)
end

Chat.AddMessage("Five seconds are really over.")
end)

On the server there is no game timer; Lua's os.time() gives you whole seconds.

tip

Thread.Pause(0) means "give up the rest of this tick and continue on the next one". It is the right call inside a loop that has to run every frame. A smaller value buys you nothing, because the next tick is the earliest the thread can continue either way.


Shared Functions

Create

Creates a thread with a function that is executed on the next script tick.

int threadId = Thread.Create(function threadFunc, any ...)

info

The function does not start running inside Thread.Create, not even its first line. It runs for the first time on the next tick, so anything the calling code does afterwards still happens first.

Example:

Events.Subscribe("sessionInit", function()
Thread.Create(function()
-- Get player model hash key.
local playerModel = Game.GetHashKey("M_Y_MULTIPLAYER")

-- Request model.
Game.RequestModel(playerModel)

-- Wait until model loaded.
while not Game.HasModelLoaded(playerModel) do
Game.RequestModel(playerModel)
Thread.Pause(0)
end

-- Change player model.
Game.ChangePlayerModel(Game.GetPlayerId(), playerModel)

-- Release model.
Game.MarkModelAsNoLongerNeeded(playerModel)
end)
end)

Pause

Pauses the current thread for at least the specified duration. See Timing.

Thread.Pause(int milliseconds)

warning

This function can only be used within a running thread. Calling it anywhere else raises a script error.

info

The comment in the example below is a simplification: the message is sent no sooner than every 5 seconds, and the small overshoot of each round adds up over time. If a task has to happen at an exact wall-clock moment, compare against a clock instead of relying on the pause.

Example:

Events.Subscribe("scriptInit", function()
Thread.Create(function()
while true do
Thread.Pause(5000)

-- This message is sent every 5 seconds.
Chat.AddMessage("5 seconds are over.")
end
end)
end)

Kill

Kills the specified thread on the next script tick.

Thread.Kill(int threadId)


IsAlive

Returns whether the specified thread is currently alive and running.

bool alive = Thread.IsAlive(int threadId)

warning

A thread marked for termination (via Kill) will continue to return true until it is actually terminated during the next script tick.