core/sync
sync
Types
24Atomic_Cond
Atomic_Cond :: struct {
state: Futex,
}SourceAtomic_Cond implements a condition variable, a rendezvous point for threads waiting for signalling the occurence of an event
An Atomic_Cond must not be copied after first use
Atomic_Mutex
Atomic_Mutex :: struct {
state: Atomic_Mutex_State,
}SourceAn Atomic_Mutex is a mutual exclusion lock The zero value for a Atomic_Mutex is an unlocked mutex
An Atomic_Mutex must not be copied after first use
Atomic_Mutex_State
Atomic_Mutex_State :: enum Futex {
Unlocked = 0,
Locked = 1,
Waiting = 2,
}SourceAtomic_RW_Mutex
Atomic_RW_Mutex :: struct {
state: Atomic_RW_Mutex_State,
mutex: Atomic_Mutex,
sema: Atomic_Sema,
}SourceAn Atomic_RW_Mutex is a reader/writer mutual exclusion lock. The lock can be held by any arbitrary number of readers or a single writer. The zero value for an Atomic_RW_Mutex is an unlocked mutex.
An Atomic_RW_Mutex must not be copied after first use.
Atomic_RW_Mutex_State
Atomic_RW_Mutex_State :: uintSourceAtomic_Recursive_Mutex
Atomic_Recursive_Mutex :: struct {
owner: int,
recursion: int,
mutex: Mutex,
}SourceAn Atomic_Recursive_Mutex is a recursive mutual exclusion lock The zero value for a Recursive_Mutex is an unlocked mutex
An Atomic_Recursive_Mutex must not be copied after first use
Atomic_Sema
Atomic_Sema :: struct {
count: Futex,
}SourceWhen waited upon, blocks until the internal count is greater than zero, then subtracts one. Posting to the semaphore increases the count by one, or the provided amount.
An Atomic_Sema must not be copied after first use
Auto_Reset_Event
Auto_Reset_Event :: struct {
// status == 0: Event is reset and no threads are waiting
// status == 1: Event is signalled
// status == -N: Event is reset and N threads are waiting
status: i32,
sema: Sema,
}SourceAuto-reset event.
Represents a thread synchronization primitive that, when signalled, releases one single waiting thread and then resets automatically to a state where it can be signalled again.
When a thread calls auto_reset_event_wait, its execution will be blocked, until the event is signalled by another thread. The call to auto_reset_event_signal wakes up exactly one thread waiting for the event.
Barrier
Barrier :: struct {
mutex: Mutex,
cond: Cond,
index: int,
generation_id: int,
thread_count: int,
}SourceBarrier.
A barrier is a synchronization primitive enabling multiple threads to synchronize the beginning of some computation.
When barrier_wait procedure is called by any thread, that thread will block the execution, until all threads associated with the barrier reach the same point of execution and also call barrier_wait.
When a barrier is initialized, a thread_count parameter is passed, signifying the amount of participant threads of the barrier. The barrier also keeps track of an internal atomic counter. When a thread calls barrier_wait, the internal counter is incremented. When the internal counter reaches thread_count, it is reset and all threads waiting on the barrier are unblocked.
This type of synchronization primitive can be used to synchronize "staged" workloads, where the workload is split into stages, and until all threads have completed the previous threads, no thread is allowed to start work on the next stage. In this case, after each stage, a barrier_wait shall be inserted in the thread procedure.
Example:
THREAD_COUNT :: 4
threads: [THREAD_COUNT]^thread.Thread
sync.barrier_init(barrier, THREAD_COUNT)
for _, i in threads {
threads[i] = thread.create_and_start(proc(t: ^thread.Thread) {
// Same messages will be printed together but without any interleaving
fmt.println("Getting ready!")
sync.barrier_wait(barrier)
fmt.println("Off their marks they go!")
})
}
for t in threads {
thread.destroy(t)
}Benaphore
Benaphore :: struct {
counter: i32,
sema: Sema,
}SourceBenaphore.
A benaphore is a combination of an atomic variable and a semaphore that can improve locking efficiency in a no-contention system. Acquiring a benaphore lock doesn't call into an internal semaphore, if no other thread is in the middle of a critical section.
Once a lock on a benaphore is acquired by a thread, no other thread is allowed into any critical sections, associted with the same benaphore, until the lock is released.
Cond
Cond :: struct {
impl: _Cond,
}SourceA condition variable.
Cond implements a condition variable, a rendezvous point for threads waiting for signalling the occurence of an event. Condition variables are used in conjuction with mutexes to provide a shared access to one or more shared variable.
A typical usage of condition variable is as follows. A thread that intends to modify a shared variable shall:
1. Acquire a lock on a mutex. 2. Modify the shared memory. 3. Release the lock. 3. Call cond_signal or cond_broadcast.
A thread that intends to wait on a shared variable shall:
1. Acquire a lock on a mutex. 2. Call cond_wait or cond_wait_with_timeout (will release the mutex). 3. Check the condition and keep waiting in a loop if not satisfied with result.
Note: A condition variable must not be copied after first use (e.g., after waiting on it the first time). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, condition variables are marked as #no_copy.
Futex
Futex :: u32SourceFast userspace mutual exclusion lock.
Futex is a fast userspace mutual exclusion lock, that uses a pointer to a 32-bit value as an identifier of the queue of waiting threads. The value pointed to by that pointer can be used to store extra data.
IMPORTANT: A futex must not be copied after first use (e.g., after waiting on it the first time, or signalling it). This is because, in order to coordinate with other threads, all threads must watch the same memory address. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior.
Mutex
Mutex :: struct {
impl: _Mutex,
}SourceMutual exclusion lock.
A Mutex is a mutual exclusion lock It can be used to prevent more than one thread from entering the critical section, and thus prevent access to same piece of memory by multiple threads, at the same time.
Mutex's zero-initializzed value represents an initial, unlocked state.
If another thread tries to acquire the lock, while it's already held (typically by another thread), the thread's execution will be blocked, until the lock is released. Code or memory that is "surrounded" by a mutex lock and unlock operations is said to be "guarded by a mutex".
Note: A Mutex must not be copied after first use (e.g., after locking it the first time). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, Mutexes are marked as #no_copy.
Note: If the current thread attempts to lock a mutex, while it's already holding another lock, that will cause a trivial case of deadlock. Do not use Mutex in recursive functions. In case multiple locks by the same thread are desired, use Recursive_Mutex.
Once
Once :: struct {
m: Mutex,
done: bool,
}SourceOnce action.
Once a synchronization primitive, that only allows a single entry into a critical section from a single thread.
One_Shot_Event
One_Shot_Event :: struct {
state: Futex,
}SourceOne-shot event.
A one-shot event is an associated token which is initially not present:
The one_shot_event_wait blocks the current thread until the event is made available The one_shot_event_signal procedure automatically makes the token available if its was not already.
Parker
Parker :: struct {
state: Futex,
}SourceA Parker is an associated token which is initially not present:
The park procedure blocks the current thread unless or until the token is available, at which point the token is consumed. The park_with_timeout procedures works the same as park but only blocks for the specified duration. The unpark procedure automatically makes the token available if it was not already.
RW_Mutex
RW_Mutex :: struct {
impl: _RW_Mutex,
}SourceRead-write mutual exclusion lock.
An RW_Mutex is a reader/writer mutual exclusion lock. The lock can be held by any number of readers or a single writer.
This type of synchronization primitive supports two kinds of lock operations:
- Exclusive lock (write lock)
- Shared lock (read lock)
When an exclusive lock is acquired by any thread, all other threads, attempting to acquire either an exclusive or shared lock, will be blocked from entering the critical sections associated with the read-write mutex, until the exclusive owner of the lock releases the lock.
When a shared lock is acquired by any thread, any other thread attempting to acquire a shared lock will also be able to enter all the critical sections associated with the read-write mutex. However threads attempting to acquire an exclusive lock will be blocked from entering those critical sections, until all shared locks are released.
Note: A read-write mutex must not be copied after first use (e.g., after acquiring a lock). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, mutexes are marked as #no_copy.
Note: A read-write mutex is not recursive. Do not attempt to acquire an exclusive lock more than once from the same thread, or an exclusive and shared lock on the same thread. Taking a shared lock multiple times is acceptable.
Recursive_Benaphore
Recursive_Benaphore :: struct {
counter: int,
owner: int,
recursion: i32,
sema: Sema,
}SourceRecursive benaphore.
A recursive benaphore is just like a plain benaphore, except it allows reentrancy into the critical section.
When a lock is acquired on a benaphore, all other threads attempting to acquire a lock on the same benaphore will be blocked from any critical sections, associated with the same benaphore.
When a lock is acquired on a benaphore by a thread, that thread is allowed to acquire another lock on the same benaphore. When a thread has acquired the lock on a benaphore, the benaphore will stay locked until the thread releases the lock as many times as it has been locked by the thread.
Recursive_Mutex
Recursive_Mutex :: struct {
impl: _Recursive_Mutex,
}SourceRecursive mutual exclusion lock.
Recurisve mutex is just like a plain mutex, except it allows reentrancy. In order for a thread to release the mutex for other threads, the mutex needs to be unlocked as many times, as it was locked.
When a lock is acquired on a recursive mutex, all other threads attempting to acquire a lock on the same mutex will be blocked from any critical sections, associated with the same recrusive mutex.
When a lock is acquired on a recursive mutex by a thread, that thread is allowed to acquire another lock on the same mutex. When a thread has acquired the lock on a recursive mutex, the recursive mutex will stay locked until the thread releases the lock as many times as it has been locked by the thread.
Note: A recursive mutex must not be copied after first use (e.g., after acquiring a lock). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, mutexes are marked as #no_copy.
Sema
Sema :: struct {
impl: _Sema,
}SourceSemaphore.
When waited upon, semaphore blocks until the internal count is greater than zero, then decrements the internal counter by one. Posting to the semaphore increases the count by one, or the provided amount.
This type of synchronization primitives can be useful for implementing queues. The internal counter of the semaphore can be thought of as the amount of items in the queue. After a data has been pushed to the queue, the thread shall call sema_post() procedure, increasing the counter. When a thread takes an item from the queue to do the job, it shall call sema_wait(), waiting on the semaphore counter to become non-zero and decreasing it, if necessary.
Note: A semaphore must not be copied after first use (e.g., after posting to it). This is because, in order to coordinate with other threads, all threads must watch the same memory address to know when the lock has been released. Trying to use a copy of the lock at a different memory address will result in broken and unsafe behavior. For this reason, semaphores are marked as #no_copy.
Ticket_Mutex
Ticket_Mutex :: struct {
ticket: uint,
serving: uint,
}SourceTicket lock.
A ticket lock is a mutual exclusion lock that uses "tickets" to control which thread is allowed into a critical section.
This synchronization primitive works just like spinlock, except that it implements a "fairness" guarantee, making sure that each thread gets a roughly equal amount of entries into the critical section.
This type of synchronization primitive is applicable for short critical sections in low-contention systems, as it uses a spinlock under the hood.
Wait_Group
Wait_Group :: struct {
counter: int,
mutex: Mutex,
cond: Cond,
}SourceWait group.
Wait group is a synchronization primitive used by the waiting thread to wait, until all working threads finish work.
The waiting thread first sets the number of working threads it will expect to wait for using wait_group_add call, and start waiting using wait_group_wait call. When worker threads complete their work, each of them will call wait_group_done, and after all working threads have called this procedure, the waiting thread will resume execution.
For the purpose of keeping track whether all working threads have finished their work, the wait group keeps an internal atomic counter. Initially, the waiting thread might set it to a certain non-zero amount. When each working thread completes the work, the internal counter is atomically decremented until it reaches zero. When it reaches zero, the waiting thread is unblocked. The counter is not allowed to become negative.
Note: Just like any synchronization primitives, a wait group cannot be copied after first use. See documentation for Mutex or Cond.
_Recursive_Mutex
_Recursive_Mutex :: struct {
owner: Futex,
recursion: i32,
}Source_Sema
_Sema :: struct {
atomic: Atomic_Sema,
}SourceConstants
29Atomic_Memory_Order
Atomic_Memory_Order :: intrinsics.Atomic_Memory_OrderSourceDescribes memory ordering for an atomic operation.
Modern CPU's contain multiple cores and caches specific to those cores. When a core performs a write to memory, the value is written to cache first. The issue is that a core doesn't typically see what's inside the caches of other cores. In order to make operations consistent CPU's implement mechanisms that synchronize memory operations across cores by asking other cores or by pushing data about writes to other cores.
Due to how these algorithms are implemented, the stores and loads performed by one core may seem to happen in a different order to another core. It also may happen that a core reorders stores and loads (independent of how compiler put them into the machine code). This can cause issues when trying to synchronize multiple memory locations between two cores. Which is why CPU's allow for stronger memory ordering guarantees if certain instructions or instruction variants are used.
In Odin there are 5 different memory ordering guarantees that can be provided to an atomic operation:
Relaxed: The memory access (load or store) is unordered with respect to
other memory accesses. This can be used to implement an atomic counter. Multiple threads access a single variable, but it doesn't matter when exactly it gets incremented, because it will become eventually consistent.
Consume: No loads or stores dependent on a memory location can be
reordered before a load with consume memory order. If other threads released the same memory, it becomes visible.
Acquire: No loads or stores on a memory location can be reordered before a
load of that memory location with acquire memory ordering. If other threads release the same memory, it becomes visible.
Release: No loads or stores on a memory location can be reordered after a
store of that memory location with release memory ordering. All threads that acquire the same memory location will see all writes done by the current thread.
Acq_Rel: Acquire-release memory ordering: combines acquire and release
memory orderings in the same operation.
Seq_Cst: Sequential consistency. The strongest memory ordering. A load will
always be an acquire operation, a store will always be a release operation, and in addition to that all threads observe the same order of writes.
Non-explicit atomics will always be sequentially consistent.
Atomic_Memory_Order :: enum {
Relaxed = 0, // Unordered
Consume = 1, // Monotonic
Acquire = 2,
Release = 3,
Acq_Rel = 4,
Seq_Cst = 5,
}
**Note(i386, x64)**: x86 has a very strong memory model by default. It
guarantees that all writes are ordered, stores and loads aren't reordered. In
a sense, all operations are at least acquire and release operations. If `lock`
prefix is used, all operations are sequentially consistent. If you use explicit
atomics, make sure you have the correct atomic memory order, because bugs likely
will not show up in x86, but may show up on e.g. arm. More on x86 memory
ordering can be found
[[here; https://www.cs.cmu.edu/~410-f10/doc/Intel_Reordering_318147.pdf]]Atomic_RW_Mutex_State_Is_Writing
Atomic_RW_Mutex_State_Is_Writing :: _ = Atomic_RW_Mutex_State(1) << (size_of(Atomic_RW_Mutex_State)*8-1)SourceAtomic_RW_Mutex_State_Reader
Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State = Atomic_RW_Mutex_State(1)SourceAtomic_RW_Mutex_State_Reader_Mask
Atomic_RW_Mutex_State_Reader_Mask :: _ = ~Atomic_RW_Mutex_State_Is_WritingSourceatomic_add
atomic_add :: intrinsics.atomic_addSourceAtomically add a value to the value stored in memory.
This procedure loads a value from memory, adds the specified value to it, and stores it back as an atomic operation. This operation is an atomic equivalent of the following:
dst^ += val
The memory ordering of this operation is sequentially-consistent.atomic_add_explicit
atomic_add_explicit :: intrinsics.atomic_add_explicitSourceAtomically add a value to the value stored in memory.
This procedure loads a value from memory, adds the specified value to it, and stores it back as an atomic operation. This operation is an atomic equivalent of the following:
dst^ += val
The memory ordering of this operation is as specified by the `order` parameter.atomic_and
atomic_and :: intrinsics.atomic_andSourceAtomically replace the memory location with the result of AND operation with the specified value.
This procedure loads a value from memory, calculates the result of AND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ &= val
The memory ordering of this operation is sequentially-consistent.atomic_and_explicit
atomic_and_explicit :: intrinsics.atomic_and_explicitSourceAtomically replace the memory location with the result of AND operation with the specified value.
This procedure loads a value from memory, calculates the result of AND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ &= val
The memory ordering of this operation is as specified by the `order` parameter.atomic_compare_exchange_strong
atomic_compare_exchange_strong :: intrinsics.atomic_compare_exchange_strongSourceAtomically compare and exchange the value with a memory location.
This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.
This procedure is an atomic equivalent of the following operation:
old_dst := dst^
if old_dst == old {
dst^ = new
return old_dst, true
} else {
return old_dst, false
}
The strong version of compare exchange always returns true, when the returned
old value stored in location pointed to by `dst` and the `old` parameter are
equal.
Atomic compare exchange has two memory orderings: One is for the
read-modify-write operation, if the comparison succeeds, and the other is for
the load operation, if the comparison fails. The memory ordering for both of
of these operations is sequentially-consistent.atomic_compare_exchange_strong_explicit
atomic_compare_exchange_strong_explicit :: intrinsics.atomic_compare_exchange_strong_explicitSourceAtomically compare and exchange the value with a memory location.
This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.
This procedure is an atomic equivalent of the following operation:
old_dst := dst^
if old_dst == old {
dst^ = new
return old_dst, true
} else {
return old_dst, false
}
The strong version of compare exchange always returns true, when the returned
old value stored in location pointed to by `dst` and the `old` parameter are
equal.
Atomic compare exchange has two memory orderings: One is for the
read-modify-write operation, if the comparison succeeds, and the other is for
the load operation, if the comparison fails. The memory ordering for these
operations is as specified by `success` and `failure` parameters respectively.atomic_compare_exchange_weak
atomic_compare_exchange_weak :: intrinsics.atomic_compare_exchange_weakSourceAtomically compare and exchange the value with a memory location.
This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.
This procedure is an atomic equivalent of the following operation:
old_dst := dst^
if old_dst == old {
// may return false here
dst^ = new
return old_dst, true
} else {
return old_dst, false
}
The weak version of compare exchange may return false, even if `dst^ == old`.
On some platforms running weak compare exchange in a loop is faster than a
strong version.
Atomic compare exchange has two memory orderings: One is for the
read-modify-write operation, if the comparison succeeds, and the other is for
the load operation, if the comparison fails. The memory ordering for both
of these operations is sequentially-consistent.atomic_compare_exchange_weak_explicit
atomic_compare_exchange_weak_explicit :: intrinsics.atomic_compare_exchange_weak_explicitSourceAtomically compare and exchange the value with a memory location.
This procedure checks if the value pointed to by the dst parameter is equal to old, and if they are, it stores the value new into the memory location, all done in a single atomic operation. This procedure returns the old value stored in a memory location and a boolean value signifying whether old was equal to new.
This procedure is an atomic equivalent of the following operation:
old_dst := dst^
if old_dst == old {
// may return false here
dst^ = new
return old_dst, true
} else {
return old_dst, false
}
The weak version of compare exchange may return false, even if `dst^ == old`.
On some platforms running weak compare exchange in a loop is faster than a
strong version.
Atomic compare exchange has two memory orderings: One is for the
read-modify-write operation, if the comparison succeeds, and the other is for
the load operation, if the comparison fails. The memory ordering for these
operations is as specified by the `success` and `failure` parameters
respectively.atomic_exchange
atomic_exchange :: intrinsics.atomic_exchangeSourceAtomically exchange the value in a memory location, with the specified value.
This procedure loads a value from the specified memory location, and stores the specified value into that memory location. Then the loaded value is returned, all done in a single atomic operation. This operation is an atomic equivalent of the following:
tmp := dst^
dst^ = val
return tmp
The memory ordering of this operation is sequentially-consistent.atomic_exchange_explicit
atomic_exchange_explicit :: intrinsics.atomic_exchange_explicitSourceAtomically exchange the value in a memory location, with the specified value.
This procedure loads a value from the specified memory location, and stores the specified value into that memory location. Then the loaded value is returned, all done in a single atomic operation. This operation is an atomic equivalent of the following:
tmp := dst^
dst^ = val
return tmp
The memory ordering of this operation is as specified by the `order` parameter.atomic_load
atomic_load :: intrinsics.atomic_loadSourceAtomically load a value from memory.
This procedure loads a value from a memory location in such a way that the received value is not a partial read. The memory ordering of this operation is sequentially-consistent.
atomic_load_explicit
atomic_load_explicit :: intrinsics.atomic_load_explicitSourceAtomically load a value from memory with explicit memory ordering.
This procedure loads a value from a memory location in such a way that the received value is not a partial read. The memory ordering of this operation is as specified by the order parameter.
atomic_nand
atomic_nand :: intrinsics.atomic_nandSourceAtomically replace the memory location with the result of NAND operation with the specified value.
This procedure loads a value from memory, calculates the result of NAND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ = ~(dst^ & val)
The memory ordering of this operation is sequentially-consistent.atomic_nand_explicit
atomic_nand_explicit :: intrinsics.atomic_nand_explicitSourceAtomically replace the memory location with the result of NAND operation with the specified value.
This procedure loads a value from memory, calculates the result of NAND operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ = ~(dst^ & val)
The memory ordering of this operation is as specified by the `order` parameter.atomic_or
atomic_or :: intrinsics.atomic_orSourceAtomically replace the memory location with the result of OR operation with the specified value.
This procedure loads a value from memory, calculates the result of OR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ |= val
The memory ordering of this operation is sequentially-consistent.atomic_or_explicit
atomic_or_explicit :: intrinsics.atomic_or_explicitSourceAtomically replace the memory location with the result of OR operation with the specified value.
This procedure loads a value from memory, calculates the result of OR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ |= val
The memory ordering of this operation is as specified by the `order` parameter.atomic_signal_fence
atomic_signal_fence :: intrinsics.atomic_signal_fenceSourceEstablish memory ordering between a current thread and a signal handler.
This procedure establishes memory ordering between a thread and a signal handler, that run on the same thread, without an associated atomic operation. This procedure is equivalent to atomic_thread_fence, except it doesn't issue any CPU instructions for memory ordering.
atomic_store
atomic_store :: intrinsics.atomic_storeSourceAtomically store a value into memory.
This procedure stores a value to a memory location in such a way that no other thread is able to see partial reads. This operation is sequentially-consistent.
atomic_store_explicit
atomic_store_explicit :: intrinsics.atomic_store_explicitSourceAtomically store a value into memory with explicit memory ordering.
This procedure stores a value to a memory location in such a way that no other thread is able to see partial reads. The memory ordering of this operation is as specified by the order parameter.
atomic_sub
atomic_sub :: intrinsics.atomic_subSourceAtomically subtract a value from the value stored in memory.
This procedure loads a value from memory, subtracts the specified value from it, and stores the result back as an atomic operation. This operation is an atomic equivalent of the following:
dst^ -= val
The memory ordering of this operation is sequentially-consistent.atomic_sub_explicit
atomic_sub_explicit :: intrinsics.atomic_sub_explicitSourceAtomically subtract a value from the value stored in memory.
This procedure loads a value from memory, subtracts the specified value from it, and stores the result back as an atomic operation. This operation is an atomic equivalent of the following:
dst^ -= val
The memory ordering of this operation is as specified by the `order` parameter.atomic_thread_fence
atomic_thread_fence :: intrinsics.atomic_thread_fenceSourceEstablish memory ordering.
This procedure establishes memory ordering, without an associated atomic operation.
atomic_xor
atomic_xor :: intrinsics.atomic_xorSourceAtomically replace the memory location with the result of XOR operation with the specified value.
This procedure loads a value from memory, calculates the result of XOR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ ~= val
The memory ordering of this operation is sequentially-consistent.atomic_xor_explicit
atomic_xor_explicit :: intrinsics.atomic_xor_explicitSourceAtomically replace the memory location with the result of XOR operation with the specified value.
This procedure loads a value from memory, calculates the result of XOR operation between the loaded value and the specified value, and stores it back into the same memory location as an atomic operation. This operation is an atomic equivalent of the following:
dst^ ~= val
The memory ordering of this operation is as specified by the `order` parameter.cpu_relax
cpu_relax :: intrinsics.cpu_relaxSourceThis procedure may lower CPU consumption or yield to a hyperthreaded twin processor. It's exact function is architecture specific, but the intent is to say that you're not doing much on a CPU.
Procedures
95_current_thread_id
_current_thread_id :: proc() -> (int)Source_current_thread_id
_current_thread_id :: proc() -> (int)Source_futex_broadcast
_futex_broadcast :: proc(futex: ^Futex)Source_futex_broadcast
_futex_broadcast :: proc(f: ^Futex)Source_futex_signal
_futex_signal :: proc(futex: ^Futex)Source_futex_signal
_futex_signal :: proc(f: ^Futex)Source_futex_wait
_futex_wait :: proc(futex: ^Futex, expected: u32) -> (bool)Source_futex_wait
_futex_wait :: proc(f: ^Futex, expected: u32) -> (bool)SourceNOTE: because core:sync is in the dependency chain of a lot of the core packages (mostly through core:mem) without actually calling into it much, I opted for a runtime panic instead of a compile error here.
_futex_wait_with_timeout
_futex_wait_with_timeout :: proc(futex: ^Futex, expected: u32, duration: time.Duration) -> (bool)Source_futex_wait_with_timeout
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> (bool)Source_recursive_mutex_lock
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex)Source_recursive_mutex_try_lock
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> (bool)Source_recursive_mutex_unlock
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex)Source_sema_post
_sema_post :: proc(s: ^Sema, count: untyped integer = 1)Source_sema_wait
_sema_wait :: proc(s: ^Sema)Source_sema_wait_with_timeout
_sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> (bool)Sourceatomic_cond_broadcast
atomic_cond_broadcast :: proc(c: ^Atomic_Cond)Sourceatomic_cond_signal
atomic_cond_signal :: proc(c: ^Atomic_Cond)Sourceatomic_cond_wait
atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex)Sourceatomic_cond_wait_with_timeout
atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool)Sourceatomic_mutex_guard
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> (bool)SourceExample:
if atomic_mutex_guard(&m) {
...
}atomic_mutex_lock
atomic_mutex_lock :: proc(m: ^Atomic_Mutex)Sourceatomic_mutex_lock locks m
atomic_mutex_try_lock
atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> (bool)Sourceatomic_mutex_try_lock tries to lock m, will return true on success, and false on failure
atomic_mutex_unlock
atomic_mutex_unlock :: proc(m: ^Atomic_Mutex)Sourceatomic_mutex_unlock unlocks m
atomic_recursive_mutex_guard
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> (bool)SourceExample:
if atomic_recursive_mutex_guard(&m) {
...
}atomic_recursive_mutex_lock
atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex)Sourceatomic_recursive_mutex_try_lock
atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> (bool)Sourceatomic_recursive_mutex_unlock
atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex)Sourceatomic_rw_mutex_guard
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> (bool)SourceExample:
if atomic_rw_mutex_guard(&m) {
...
}atomic_rw_mutex_lock
atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex)Sourceatomic_rw_mutex_lock locks rw for writing (with a single writer) If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
atomic_rw_mutex_shared_guard
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> (bool)SourceExample:
if atomic_rw_mutex_shared_guard(&m) {
...
}atomic_rw_mutex_shared_lock
atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex)Sourceatomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
atomic_rw_mutex_shared_unlock
atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex)Sourceatomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
atomic_rw_mutex_try_lock
atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> (bool)Sourceatomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)
atomic_rw_mutex_try_shared_lock
atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> (bool)Sourceatomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
atomic_rw_mutex_unlock
atomic_rw_mutex_unlock :: proc(rw: ^Atomic_RW_Mutex)Sourceatomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
atomic_sema_post
atomic_sema_post :: proc(s: ^Atomic_Sema, count: untyped integer = 1)Sourceatomic_sema_wait
atomic_sema_wait :: proc(s: ^Atomic_Sema)Sourceatomic_sema_wait_with_timeout
atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) -> (bool)Sourceauto_reset_event_signal
auto_reset_event_signal :: proc(e: ^Auto_Reset_Event)SourceSignal an auto-reset event.
This procedure signals an auto-reset event, waking up exactly one waiting thread.
auto_reset_event_wait
auto_reset_event_wait :: proc(e: ^Auto_Reset_Event)SourceWait on an auto-reset event.
This procedure blocks the execution of the current thread, until the event is signalled by another thread.
barrier_init
barrier_init :: proc(b: ^Barrier, thread_count: int)SourceInitialize a barrier.
This procedure initializes the barrier for the specified amount of participant threads.
barrier_wait
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool)SourceBlock the current thread until all threads have rendezvoused.
This procedure blocks the execution of the current thread, until all threads have reached the same point in the execution of the thread proc. Multiple calls to barrier_wait are allowed within the thread procedure.
benaphore_guard
benaphore_guard :: proc(m: ^Benaphore) -> (bool)SourceGuard the current scope with a lock on a benaphore.
This procedure acquires a lock on a benaphore. The lock is automatically released at the end of callee's scope. If the benaphore was already locked, this procedure also blocks until the lock can be acquired.
When a lock has been acquired, all threads attempting to acquire a lock will be blocked from entering any critical sections associated with the same benaphore, until the lock is released.
This procedure always returns true. This makes it easy to define a critical section by putting the function inside the if statement.
Example:
if benaphore_guard(&m) {
...
}benaphore_lock
benaphore_lock :: proc(b: ^Benaphore)SourceAcquire a lock on a benaphore.
This procedure acquires a lock on the specified benaphore. If the lock on a benaphore is already held, this procedure also blocks the execution of the current thread, until the lock could be acquired.
Once a lock is acquired, all threads attempting to take a lock will be blocked from entering any critical sections associated with the same benaphore, until until the lock is released.
benaphore_try_lock
benaphore_try_lock :: proc(b: ^Benaphore) -> (bool)SourceTry to acquire a lock on a benaphore.
This procedure tries to acquire a lock on the specified benaphore. If it was already locked, then the returned value is false, otherwise the lock is acquired and the procedure returns true.
If the lock is acquired, all threads that attempt to acquire a lock will be blocked from entering any critical sections associated with the same benaphore, until the lock is released.
benaphore_unlock
benaphore_unlock :: proc(b: ^Benaphore)SourceRelease a lock on a benaphore.
This procedure releases a lock on the specified benaphore. If any of the threads are waiting on the lock, exactly one thread is allowed into a critical section associated with the same benaphore.
cond_broadcast
cond_broadcast :: proc(c: ^Cond)SourceWake up all threads that wait on a condition variable.
This procedure causes all threads waiting on the condition variable to wake up.
cond_signal
cond_signal :: proc(c: ^Cond)SourceWake up one thread that waits on a condition variable.
This procedure causes exactly one thread waiting on the condition variable to wake up.
cond_wait
cond_wait :: proc(c: ^Cond, m: ^Mutex)SourceWait until the condition variable is signalled and release the associated mutex.
This procedure blocks the current thread until the specified condition variable is signalled, or until a spurious wakeup occurs. In addition, if the condition has been signalled, this procedure releases the lock on the specified mutex.
The mutex must be held by the calling thread, before calling the procedure.
Note: This procedure can return on a spurious wake-up, even if the condition variable was not signalled by a thread.
cond_wait_with_timeout
cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> (bool)SourceWait until the condition variable is signalled or timeout is reached and release the associated mutex.
This procedure blocks the current thread until the specified condition variable is signalled, a timeout is reached, or until a spurious wakeup occurs. In addition, if the condition has been signalled, this procedure releases the lock on the specified mutex.
If the timeout was reached, this procedure returns false. Otherwise it returns true.
Before this procedure is called the mutex must be held by the calling thread.
current_thread_id
current_thread_id :: proc() -> (int)SourceObtain the current thread ID.
futex_broadcast
futex_broadcast :: proc(f: ^Futex)SourceWake up multiple threads waiting on a futex.
futex_signal
futex_signal :: proc(f: ^Futex)SourceWake up a single thread waiting on a futex.
futex_wait
futex_wait :: proc(f: ^Futex, expected: u32)SourceSleep if the futex contains the expected value until it's signalled.
If the value of the futex is expected, this procedure blocks the execution of the current thread, until the futex is woken up, or until a spurious wakeup occurs.
futex_wait_with_timeout
futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> (bool)SourceSleep if the futex contains the expected value until it's signalled or the timeout is reached.
If the value of the futex is expected, this procedure blocks the execution of the current thread, until the futex is signalled, a timeout is reached, or until a spurious wakeup occurs.
This procedure returns false if the timeout was reached, true otherwise.
mutex_guard
mutex_guard :: proc(m: ^Mutex) -> (bool)SourceGuard the current scope with a lock on a mutex.
This procedure acquires a mutex lock. The lock is automatically released at the end of callee's scope. If the mutex was already locked, this procedure also blocks until the lock can be acquired.
When a lock has been acquired, all threads attempting to acquire a lock will be blocked from entering any critical sections associated with the mutex, until the lock is released.
This procedure always returns true. This makes it easy to define a critical section by putting the function inside the if statement.
Example:
if mutex_guard(&m) {
...
}mutex_lock
mutex_lock :: proc(m: ^Mutex)SourceAcquire a lock on a mutex.
This procedure acquires a lock with the specified mutex. If the mutex has been already locked by any thread, this procedure also blocks until the lock can be acquired.
Once the lock is acquired, all other threads that attempt to acquire a lock will be blocked from entering any critical sections associated with the same mutex, until the the lock is released.
Note: If the mutex is already locked by the current thread, a call to this procedure will block indefinately. Do not use this in recursive procedures.
mutex_try_lock
mutex_try_lock :: proc(m: ^Mutex) -> (bool)SourceTry to acquire a lock on a mutex.
This procedure tries to acquire a lock on the specified mutex. If it was already locked, then the returned value is false, otherwise the lock is acquired and the procedure returns true.
If the lock is acquired, all threads that attempt to acquire a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.
mutex_unlock
mutex_unlock :: proc(m: ^Mutex)SourceRelease a lock on a mutex.
This procedure releases the lock associated with the specified mutex. If the mutex was not locked, this operation is a no-op.
When the current thread, that holds a lock to the mutex calls mutex_unlock, this allows one other thread waiting on the mutex to enter any critical sections associated with the mutex. If there are no threads waiting on the mutex, the critical sections will remain open.
once_do_with_data
once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr)SourceCall a function with data once.
once_do_with_data_contextless
once_do_with_data_contextless :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr)SourceCall a contextless function with data once.
once_do_without_data
once_do_without_data :: proc(o: ^Once, fn: proc())SourceCall a function with no data once.
once_do_without_data_contextless
once_do_without_data_contextless :: proc(o: ^Once, fn: proc())SourceCall a contextless function with no data once.
one_shot_event_signal
one_shot_event_signal :: proc(e: ^One_Shot_Event)SourceMake event available.
one_shot_event_wait
one_shot_event_wait :: proc(e: ^One_Shot_Event)SourceBlock until the event is made available.
This procedure blocks the execution of the current thread, until the event is made available.
park
park :: proc(p: ^Parker)SourceBlocks until the token is available.
This procedure blocks the execution of the current thread, until a token is made available.
Note: This procedure assumes this is only called by the thread that owns the Parker.
park_with_timeout
park_with_timeout :: proc(p: ^Parker, duration: time.Duration)SourceBlocks until the token is available with timeout.
This procedure blocks the execution of the current thread until a token is made available, or until the timeout has expired, whatever happens first.
Note: This procedure assumes this is only called by the thread that owns the Parker.
recursive_benaphore_guard
recursive_benaphore_guard :: proc(m: ^Recursive_Benaphore) -> (bool)SourceGuard the current scope with a recursive benaphore.
This procedure acquires a lock on the specified recursive benaphores and automatically releases it at the end of the callee's scope. If the recursive benaphore was already held by a another thread, this procedure also blocks until the lock can be acquired.
When the lock is acquired all other threads attempting to take a lock will be blocked from entering any critical sections associated with the same benaphore, until the lock is released.
This procedure always returns true, which makes it easy to define a critical section by calling this procedure inside an if statement.
Example:
if recursive_benaphore_guard(&m) {
...
}recursive_benaphore_lock
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore)SourceAcquire a lock on a recursive benaphore.
This procedure acquires a lock on a recursive benaphore. If the benaphore is held by another thread, this function blocks until the lock can be acquired.
Once a lock is acquired, all other threads attempting to acquire a lock will be blocked from entering any critical sections associated with the same recursive benaphore, until the lock is released.
recursive_benaphore_try_lock
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> (bool)SourceTry to acquire a lock on a recursive benaphore.
This procedure attempts to acquire a lock on recursive benaphore. If the benaphore is already held by a different thread, this procedure returns false. Otherwise the lock is acquired and the procedure returns true.
If the lock is acquired, all other threads attempting to acquire a lock will be blocked from entering any critical sections assciated with the same recursive benaphore, until the lock is released.
recursive_benaphore_unlock
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore)SourceRelease a lock on a recursive benaphore.
This procedure releases a lock on the specified recursive benaphore. It also causes the critical sections associated with the same benaphore, to become open for other threads for entering.
recursive_mutex_guard
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> (bool)SourceGuard the scope with a recursive mutex lock.
This procedure acquires a lock on the specified recursive mutex and automatically releases it at the end of the callee's scope. If the recursive mutex was already held by a another thread, this procedure also blocks until the lock can be acquired.
When the lock is acquired all other threads attempting to take a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.
This procedure always returns true, which makes it easy to define a critical section by calling this procedure inside an if statement.
Example:
if recursive_mutex_guard(&m) {
...
}recursive_mutex_lock
recursive_mutex_lock :: proc(m: ^Recursive_Mutex)SourceAcquire a lock on a recursive mutex.
This procedure acquires a lock on the specified recursive mutex. If the lock is acquired by a different thread, this procedure also blocks until the lock can be acquired.
When the lock is acquired, all other threads attempting to acquire a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.
recursive_mutex_try_lock
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> (bool)SourceTry to acquire a lock on a recursive mutex.
This procedure attempts to acquire a lock on the specified recursive mutex. If the recursive mutex is locked by other threads, this procedure returns false. Otherwise it locks the mutex and returns true.
If the lock is acquired, all other threads attempting to obtain a lock will be blocked from entering any critical sections associated with the same mutex, until the lock is released.
recursive_mutex_unlock
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex)SourceRelease a lock on a recursive mutex.
This procedure releases a lock on the specified recursive mutex. It also causes the critical sections associated with the same mutex, to become open for other threads for entering.
rw_mutex_guard
rw_mutex_guard :: proc(m: ^RW_Mutex) -> (bool)SourceGuard the current scope with an exclusive lock on a read-write mutex.
This procedure acquires an exclusive lock on the specified read-write mutex. This procedure automatically releases the lock at the end of the callee's scope. If the mutex was already locked by readers or a writer, this procedure blocks, until a lock can be acquired.
When an exclusive lock is acquired, all other threads attempting to acquire an exclusive lock will be blocked from entering any critical sections associated with the same read-write mutex, until the exclusive lock is released.
This procedure always returns true, which makes it easy to define a critical section by running this procedure inside an if statement.
Example:
if rw_mutex_guard(&m) {
...
}rw_mutex_lock
rw_mutex_lock :: proc(rw: ^RW_Mutex)SourceAcquire an exclusive lock.
This procedure acquires an exclusive lock on the specified read-write mutex. If the lock is already held by any thread, this procedure also blocks until the lock can be acquired.
After a lock has been acquired, any thread attempting to acquire any lock will be blocked from entering any critical sections associated with the same read-write mutex, until the exclusive lock is released.
rw_mutex_shared_guard
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> (bool)SourceGuard the current scope with a shared lock on a read-write mutex.
This procedure acquires a shared lock on the specified read-write mutex. This procedure automatically releases the lock at the end of the callee's scope. If the mutex already has an associated exclusive lock, this procedure blocks, until a lock can be acquired.
When a shared lock is obtained, all other threads attempting to obtain an exclusive lock will be blocked from any critical sections, associated with the same read-write mutex, until all shared locks are released.
This procedure always returns true, which makes it easy to define a critical section by running this procedure inside an if statement.
Example:
if rw_mutex_guard(&m) {
...
}rw_mutex_shared_lock
rw_mutex_shared_lock :: proc(rw: ^RW_Mutex)SourceAcquire a shared lock on a read-write mutex.
This procedure acquires a shared lock on the specified read-write mutex. If the mutex already has an exclusive lock held, this procedure also blocks until the lock can be acquired.
After the shared lock is obtained, all threads attempting to acquire an exclusive lock will be blocked from entering any critical sections associated with the same read-write mutex, until all shared locks associated with the specified read-write mutex are released.
rw_mutex_shared_unlock
rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex)SourceRelease the shared lock on a read-write mutex.
This procedure releases shared lock on the specified read-write mutex. When all shared locks are released, all critical sections associated with the same read-write mutex become open to other threads.
rw_mutex_try_lock
rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> (bool)SourceTry to acquire an exclusive lock on a read-write mutex.
This procedure tries to acquire an exclusive lock on the specified read-write mutex. If the mutex was already locked, the procedure returns false. Otherwise it acquires the exclusive lock and returns true.
If the lock has been acquired, all threads attempting to acquire any lock will be blocked from entering any critical sections associated with the same read-write mutex, until the exclusive locked is released.
rw_mutex_try_shared_lock
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> (bool)SourceTry to acquire a shared lock on a read-write mutex.
This procedure attempts to acquire a lock on the specified read-write mutex. If the mutex already has an exclusive lock held, this procedure returns false. Otherwise, it acquires the lock on the mutex and returns true.
If the shared lock has been acquired, it causes all threads attempting to acquire the exclusive lock to be blocked from entering any critical sections associated with the same read-write mutex, until all shared locks are released.
rw_mutex_unlock
rw_mutex_unlock :: proc(rw: ^RW_Mutex)SourceRelease an exclusive lock.
This procedure releases an exclusive lock associated with the specified read-write mutex.
When the exclusive lock is released, all critical sections, associated with the same read-write mutex, become open to other threads.
sema_post
sema_post :: proc(s: ^Sema, count: untyped integer = 1)SourceIncrement the internal counter on a semaphore by the specified amount.
This procedure increments the internal counter of the semaphore. If any of the threads were waiting on the semaphore, up to count of threads will continue the execution and enter the critical section.
sema_wait
sema_wait :: proc(s: ^Sema)SourceWait on a semaphore until the internal counter is non-zero.
This procedure blocks the execution of the current thread, until the semaphore counter is non-zero, and atomically decrements it by one, once the wait has ended.
sema_wait_with_timeout
sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> (bool)SourceWait on a semaphore until the internal counter is non-zero or a timeout is reached.
This procedure blocks the execution of the current thread, until the semaphore counter is non-zero, and if so atomically decrements it by one, once the wait has ended. If the specified timeout is reached, the function returns false, otherwise it returns true.
ticket_mutex_guard
ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> (bool)SourceGuard the current scope with a lock on a ticket mutex.
This procedure acquires a lock on a ticket mutex. The lock is automatically released at the end of callee's scope. If the mutex was already locked, this procedure also blocks until the lock can be acquired.
When a lock has been acquired, all threads attempting to acquire a lock will be blocked from entering any critical sections associated with the ticket mutex, until the lock is released.
This procedure always returns true. This makes it easy to define a critical section by putting the function inside the if statement.
Example:
if ticket_mutex_guard(&m) {
...
}ticket_mutex_lock
ticket_mutex_lock :: proc(m: ^Ticket_Mutex)SourceAcquire a lock on a ticket mutex.
This procedure acquires a lock on a ticket mutex. If the ticket mutex is held by another thread, this procedure also blocks the execution until the lock can be acquired.
Once the lock is acquired, any thread calling ticket_mutex_lock will be blocked from entering any critical sections associated with the same ticket mutex, until the lock is released.
ticket_mutex_unlock
ticket_mutex_unlock :: proc(m: ^Ticket_Mutex)SourceRelease a lock on a ticket mutex.
This procedure releases the lock on a ticket mutex. If any of the threads are waiting to acquire the lock, exactly one of those threads is unblocked and allowed into the critical section.
unpark
unpark :: proc(p: ^Parker)SourceMake the token available.
wait_group_add
wait_group_add :: proc(wg: ^Wait_Group, delta: int)SourceIncrement an internal counter of a wait group.
This procedure atomically increments a number to the specified wait group's internal counter by a specified amount. This operation can be done on any thread.
wait_group_done
wait_group_done :: proc(wg: ^Wait_Group)SourceSignal work done by a thread in a wait group.
This procedure decrements the internal counter of the specified wait group and wakes up the waiting thread. Once the internal counter reaches zero, the waiting thread resumes execution.
wait_group_wait
wait_group_wait :: proc(wg: ^Wait_Group)SourceWait for all worker threads in the wait group.
This procedure blocks the execution of the current thread, until the specified wait group's internal counter reaches zero.
wait_group_wait_with_timeout
wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -> (bool)SourceWait for all worker threads in the wait group, or until timeout is reached.
This procedure blocks the execution of the current thread, until the specified wait group's internal counter reaches zero, or until the timeout is reached.
This procedure returns false, if the timeout was reached, true otherwise.
Procedure Groups
14broadcast
broadcast :: proc{cond_broadcast, atomic_cond_broadcast, futex_broadcast}Sourceguard
guard :: proc{mutex_guard, rw_mutex_guard, recursive_mutex_guard, ticket_mutex_guard, benaphore_guard, recursive_benaphore_guard, atomic_mutex_guard, atomic_recursive_mutex_guard, atomic_rw_mutex_guard}SourceExample:
if guard(&m) {
...
}lock
lock :: proc{mutex_lock, rw_mutex_lock, recursive_mutex_lock, ticket_mutex_lock, benaphore_lock, recursive_benaphore_lock, atomic_mutex_lock, atomic_recursive_mutex_lock, atomic_rw_mutex_lock}Sourcelock locks m
once_do
once_do :: proc{once_do_without_data, once_do_without_data_contextless, once_do_with_data, once_do_with_data_contextless}SourceCall a function once.
The once_do procedure group calls a specified function, if it wasn't already called from the perspective of a specific Once struct.
post
post :: proc{sema_post, atomic_sema_post}Sourceshared_guard
shared_guard :: proc{rw_mutex_shared_guard, atomic_rw_mutex_shared_guard}SourceExample:
if shared_guard(&m) {
...
}shared_lock
shared_lock :: proc{rw_mutex_shared_lock, atomic_rw_mutex_shared_lock}Sourceshared_lock locks rw for reading (with arbitrary number of readers)
shared_unlock
shared_unlock :: proc{rw_mutex_shared_unlock, atomic_rw_mutex_shared_unlock}Sourceshared_unlock unlocks rw for reading (with arbitrary number of readers)
signal
signal :: proc{cond_signal, atomic_cond_signal, futex_signal}Sourcetry_lock
try_lock :: proc{mutex_try_lock, rw_mutex_try_lock, recursive_mutex_try_lock, benaphore_try_lock, recursive_benaphore_try_lock, atomic_mutex_try_lock, atomic_recursive_mutex_try_lock, atomic_rw_mutex_try_lock}Sourcetry_lock tries to lock m, will return true on success, and false on failure
try_shared_lock
try_shared_lock :: proc{rw_mutex_try_shared_lock, atomic_rw_mutex_try_shared_lock}Sourcetry_shared_lock tries to lock rw for reading (with arbitrary number of readers)
unlock
unlock :: proc{mutex_unlock, rw_mutex_unlock, recursive_mutex_unlock, ticket_mutex_unlock, benaphore_unlock, recursive_benaphore_unlock, atomic_mutex_unlock, atomic_recursive_mutex_unlock, atomic_rw_mutex_unlock}Sourceunlock locks m
wait
wait :: proc{cond_wait, sema_wait, atomic_cond_wait, atomic_sema_wait, futex_wait, wait_group_wait}Sourcewait_with_timeout
wait_with_timeout :: proc{cond_wait_with_timeout, sema_wait_with_timeout, atomic_cond_wait_with_timeout, atomic_sema_wait_with_timeout, futex_wait_with_timeout, wait_group_wait_with_timeout}Source