###### 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.