###### tags: `Guide To Contibuting`
# Timing/Synchronization/Threading
### A note on BYOND
**There is no true multithreading in BYOND.** BYOND is 32 bit and single cored and a relic. No, you can not take advantage of multiple processor cores. The closest you get is asynchronity in the barest forms with the following.
### Procs
#### BYOND scheduling
BYOND has an internal scheduler that allows pausing and resuming of procs. It's inefficient and bad, more on that in the following:
#### `sleep(x)` (default byond proc)
Delays the current proc by `x` deciseconds. This will hold up anything waiting on or for the proc unless it's `set waitfor = FALSE`'d.
##### `stoplag(x)`
This basically sleep's for x seconds but will sleep longer if the server is chugging. Useful at times for delaying things that don't need to be precisely timed.
##### `UNTIL(condition)`
This stoplag()s until condition is true. It's an infinite loop, that holds the proc up without making the server hang, basically. Don't use it unless you really need to.
#### `spawn(x)` (default byond proc)
Runs the code segment under it after `x` deciseconds. The proc it's called from keeps running and the segment is simply scheduled to run later. All variables in the proc it's running from are copied/referenced from the segment.
**THIS IS BANNED. Byond's scheduler is HORRIBLE performance-wise compared to our own timer system. Never, ever used this.**
Technical details:
This basically just runs the rest of the proc without running the stuff under it and then runs the stuff under it after the time has elapsed.
#### `addtimer(x)`
This is /tg/code (and most modern SS13 codebases actually)'s replacement for spawn(). Made by MrStonedOne.
Usage:
```DM
addtimer(CALLBACK(object, /path/to/object/where/proc/is/defined.proc/to/call, arg1, arg2, arg2), time, flags)
```
This is basically a far more efficient `spawn()`. Spawn should never ever be used, use this instead. This schedules a callback to run after `time` deciseconds.
`deltimer(id)` deletes a timer of the specified id.
`addtimer()` will return an ID if `flags` contains `TIMER_STOPPABLE`. There's also some other flags, check `code/__DEFINES/subsystems.dm` for the rest of the timer flags.
#### `set waitfor = FALSE` and `INVOKE_ASYNC(delegate, procname)`
`INVOKE_ASYNC()` is basically a wrapper for `proc() ==> (set waitfor = FALSE;call(proc))`
`waitfor` is a nifty property you can set on procs that tells it to immediately return its default return value, `.`, when anything it runs inside it tries to sleep. This is useful for absolutely ensuring that a proc doesn't block the caller from continuing to run, **but should be used sparingly. It's better to make sure you're not making anything sleep() than to rely on this too much.**
It's hard to explain when this should and shouldn't be used so I'll leave it up to learning by trial by error, unless someone wants to rewrite this subsection.
#### `/datum/callback`
This datum basically holds information about a thing to call (execute).
Read `code/datums/callback.dm` for more information but for the high level rundown:
This is used in timers so the timer knows what to do. Timers call their assigned callback asynchronously.
Usage:
`CALLBACK(object, /path/to/datum/that/defines/the/proc.procname, arg1, arg2, ...)`
- Two things to notice here
- /path/to/datum/that/defines/the/proc: You can just do .procname without this if the proc is defined on the object you're doing the CALLBACK() macro from, like if you're doing this from myobject/makecallback() and myobject has a proc named test, you can just do CALLBACK(src, .proc/test). If it isn't, however, you'll need to do the full path. For example, most of the time if you try to callback update_icon, since it's first defined on /atom and not on its subtypes, you'd need to do CALLBACK(src, /atom.proc/update_icon)
- Arguments are carried over.
- CALLBACK() is just a fancy way of doing new /datum/callback(object, procname, ...)
`CALLBACK(GLOBAL_PROC, .proc/procname)` - For global procs. You literally type in GLOBAL_PROC.