sync #
Description
sync
provides cross platform handling of concurrency primitives.
fn channel_select #
fn channel_select(mut channels []&Channel, dir []Direction, mut objrefs []voidptr, timeout time.Duration) int
Wait timeout
on any of channels[i]
until one of them can push (is_push[i] = true
) or pop (is_push[i] = false
) object referenced by objrefs[i]
. timeout = time.infinite
means wait unlimited time. timeout <= 0
means return immediately if no transaction can be performed without waiting. return value: the index of the channel on which a transaction has taken place -1 if waiting for a transaction has exceeded timeout -2 if all channels are closed
fn new_channel #
fn new_channel[T](n u32) &Channel
fn new_many_times #
fn new_many_times(times u64) &ManyTimes
new_many_times return a new ManyTimes struct.
fn new_mutex #
fn new_mutex() &Mutex
new_mutex creates and initialises a new mutex instance on the heap, then returns a pointer to it.
fn new_once #
fn new_once() &Once
new_once return a new Once struct.
fn new_rwmutex #
fn new_rwmutex() &RwMutex
new_rwmutex creates a new read/write mutex instance on the heap, and returns a pointer to it.
fn new_semaphore #
fn new_semaphore() &Semaphore
new_semaphore creates a new initialised Semaphore instance on the heap, and returns a pointer to it. The initial counter value of the semaphore is 0.
fn new_semaphore_init #
fn new_semaphore_init(n u32) &Semaphore
new_semaphore_init creates a new initialised Semaphore instance on the heap, and returns a pointer to it. The n
parameter can be used to set the initial counter value of the semaphore.
fn new_waitgroup #
fn new_waitgroup() &WaitGroup
fn thread_id #
fn thread_id() u64
thread_id returns a unique identifier for the caller thread. All currently running threads in the same process, will have different thread identifiers.
Note: if a thread finishes, and another starts, the identifier of the old thread may be reused for the newly started thread. In other words, thread IDs are guaranteed to be unique only within a process. A thread ID may be reused after a terminated thread has been joined (with t.wait()
), or when the thread has terminated.
enum Direction #
enum Direction {
pop
push
}
struct C.atomic_uintptr_t #
struct C.atomic_uintptr_t {}
struct C.pthread_mutex_t #
struct C.pthread_mutex_t {}
struct C.pthread_rwlock_t #
struct C.pthread_rwlock_t {}
struct C.pthread_rwlockattr_t #
struct C.pthread_rwlockattr_t {}
struct C.sem_t #
struct C.sem_t {}
struct Channel #
struct Channel {
ringbuf &u8 = unsafe { nil } // queue for buffered channels
statusbuf &u8 = unsafe { nil } // flags to synchronize write/read in ringbuf
objsize u32
mut:
// atomic
writesem Semaphore // to wake thread that wanted to write, but buffer was full
readsem Semaphore // to wake thread that wanted to read, but buffer was empty
writesem_im Semaphore
readsem_im Semaphore
write_adr C.atomic_uintptr_t // if != NULL the next obj can be written here without wait
read_adr C.atomic_uintptr_t // if != NULL an obj can be read from here without wait
adr_read C.atomic_uintptr_t // used to identify origin of writesem
adr_written C.atomic_uintptr_t // used to identify origin of readsem
write_free u32 // for queue state
read_avail u32
buf_elem_write_idx u32
buf_elem_read_idx u32
// for select
write_subscriber &Subscription = unsafe { nil }
read_subscriber &Subscription = unsafe { nil }
write_sub_mtx u16
read_sub_mtx u16
closed u16
pub:
cap u32 // queue length in #objects
}
fn (Channel) auto_str #
fn (ch &Channel) auto_str(typename string) string
fn (Channel) close #
fn (mut ch Channel) close()
fn (Channel) len #
fn (mut ch Channel) len() int
fn (Channel) closed #
fn (mut ch Channel) closed() bool
fn (Channel) push #
fn (mut ch Channel) push(src voidptr)
fn (Channel) try_push #
fn (mut ch Channel) try_push(src voidptr) ChanState
fn (Channel) pop #
fn (mut ch Channel) pop(dest voidptr) bool
fn (Channel) try_pop #
fn (mut ch Channel) try_pop(dest voidptr) ChanState
struct ManyTimes #
struct ManyTimes {
mut:
m RwMutex
pub:
times u64 = 1
count u64
}
fn (ManyTimes) do #
fn (mut m ManyTimes) do(f fn ())
do execute the function only setting times.
struct Mutex #
struct Mutex {
mutex C.pthread_mutex_t
}
[init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function.
fn (Mutex) destroy #
fn (mut m Mutex) destroy()
destroy frees the resources associated with the mutex instance.
Note: the mutex itself is not freed.
fn (Mutex) init #
fn (mut m Mutex) init()
init initialises the mutex. It should be called once before the mutex is used, since it creates the associated resources needed for the mutex to work properly.
fn (Mutex) lock #
fn (mut m Mutex) lock()
lock locks the mutex instance (lock
is a keyword). If the mutex was already locked, it will block, till it is unlocked.
fn (Mutex) str #
fn (m &Mutex) str() string
str returns a string representation of the Mutex pointer
fn (Mutex) try_lock #
fn (mut m Mutex) try_lock() bool
try_lock try to lock the mutex instance and return immediately. If the mutex was already locked, it will return false.
fn (Mutex) unlock #
fn (mut m Mutex) unlock()
unlock unlocks the mutex instance. The mutex is released, and one of the other threads, that were blocked, because they called lock can continue.
struct Once #
struct Once {
mut:
m RwMutex
pub:
count u64
}
fn (Once) do #
fn (mut o Once) do(f fn ())
do executes the function f()
only once
fn (Once) do_with_param #
fn (mut o Once) do_with_param(f fn (voidptr), param voidptr)
do_with_param executes f(param)
only once` This method can be used as a workaround for passing closures to once.do/1 on Windows (they are not implemented there yet) - just pass your data explicitly. i.e. instead of:
once.do(fn [mut o] () {
o.add(5)
})
... you can use:
once.do_with_param(fn (mut o One) {
o.add(5)
}, o)
struct RwMutex #
struct RwMutex {
mutex C.pthread_rwlock_t
}
fn (RwMutex) destroy #
fn (mut m RwMutex) destroy()
destroy frees the resources associated with the rwmutex instance.
Note: the mutex itself is not freed.
fn (RwMutex) init #
fn (mut m RwMutex) init()
init initialises the RwMutex instance. It should be called once before the rw mutex is used, since it creates the associated resources needed for the mutex to work properly.
fn (RwMutex) lock #
fn (mut m RwMutex) lock()
lock locks the given RwMutex instance for writing. If the mutex was already locked, it will block, till it is unlocked, then it will try to get the lock, and if it can, it will return, otherwise it will continue waiting for the mutex to become unlocked.
Note: there may be several threads that are waiting for the same lock.
Note: RwMutex has separate read and write locks.
fn (RwMutex) rlock #
fn (mut m RwMutex) rlock()
rlock locks the given RwMutex instance for reading. If the mutex was already locked, it will block, and will try to get the lock, once the lock is released by another thread calling unlock. Once it succeds, it returns.
Note: there may be several threads that are waiting for the same lock.
Note: RwMutex has separate read and write locks.
fn (RwMutex) runlock #
fn (mut m RwMutex) runlock()
runlock unlocks the RwMutex instance, locked for reading.
Note: Windows SRWLocks have different function to unlocking. To have a common portable API, there are two methods for unlocking here as well, even though that they do the same on !windows platforms.
fn (RwMutex) str #
fn (m &RwMutex) str() string
str returns a string representation of the RwMutex pointer
fn (RwMutex) try_rlock #
fn (mut m RwMutex) try_rlock() bool
try_rlock try to lock the given RwMutex instance for reading and return immediately. If the mutex was already locked, it will return false.
fn (RwMutex) try_wlock #
fn (mut m RwMutex) try_wlock() bool
try_wlock try to lock the given RwMutex instance for writing and return immediately. If the mutex was already locked, it will return false.
fn (RwMutex) unlock #
fn (mut m RwMutex) unlock()
unlock unlocks the RwMutex instance, locked for writing.
Note: Windows SRWLocks have different function to unlocking. To have a common portable API, there are two methods for unlocking here as well, even though that they do the same on !windows platforms.
struct Semaphore #
struct Semaphore {
sem C.sem_t
}
fn (Semaphore) init #
fn (mut sem Semaphore) init(n u32)
init initialises the Semaphore instance with n
as its initial counter value. It should be called once before the semaphore is used, since it creates the associated resources needed for the semaphore to work properly.
fn (Semaphore) post #
fn (mut sem Semaphore) post()
post increases/unlocks the counter of the semaphore by 1. If the resulting counter value is > 0, and if there is another thread waiting on the semaphore, the waiting thread will decrement the counter by 1 (locking the semaphore), and then will continue running. See also .wait() .
fn (Semaphore) wait #
fn (mut sem Semaphore) wait()
wait will just decrement the semaphore count, if it was positive. It it was not positive, it will waits for the semaphore count to reach a positive number. When that happens, it will decrease the semaphore count (lock the semaphore), and will return. In effect, it allows you to block threads, until the semaphore, is posted by another thread. See also .post() .
fn (Semaphore) try_wait #
fn (mut sem Semaphore) try_wait() bool
try_wait tries to decrease the semaphore count by 1, if it was positive. If it succeeds in that, it returns true, otherwise it returns false. try_wait should return as fast as possible so error handling is only done when debugging
fn (Semaphore) timed_wait #
fn (mut sem Semaphore) timed_wait(timeout time.Duration) bool
timed_wait is similar to .wait(), but it also accepts a timeout duration, thus it can return false early, if the timeout passed before the semaphore was posted.
fn (Semaphore) destroy #
fn (mut sem Semaphore) destroy()
destroy frees the resources associated with the Semaphore instance.
Note: the semaphore instance itself is not freed.
struct WaitGroup #
struct WaitGroup {
mut:
task_count u32 // current task count - reading/writing should be atomic
wait_count u32 // current wait count - reading/writing should be atomic
sem Semaphore // This blocks wait() until tast_countreleased by add()
}
WaitGroup Do not copy an instance of WaitGroup, use a ref instead.
usage: in main thread: wg := sync.new_waitgroup()
wg.add(nr_jobs)before starting jobs with
go ...
wg.wait()` to wait for all jobs to have finished
in each parallel job: wg.done()
when finished
[init_with=new_waitgroup] // TODO: implement support for init_with struct attribute, and disallow WaitGroup{} from outside the sync.new_waitgroup() function.
fn (WaitGroup) init #
fn (mut wg WaitGroup) init()
fn (WaitGroup) add #
fn (mut wg WaitGroup) add(delta int)
add increments (+ve delta) or decrements (-ve delta) task count by delta and unblocks any wait() calls if task count becomes zero. add panics if task count drops below zero.
fn (WaitGroup) done #
fn (mut wg WaitGroup) done()
done is a convenience fn for add(-1)
fn (WaitGroup) wait #
fn (mut wg WaitGroup) wait()
wait blocks until all tasks are done (task count becomes zero)
- README
- fn channel_select
- fn new_channel
- fn new_many_times
- fn new_mutex
- fn new_once
- fn new_rwmutex
- fn new_semaphore
- fn new_semaphore_init
- fn new_waitgroup
- fn thread_id
- enum Direction
- struct C.atomic_uintptr_t
- struct C.pthread_mutex_t
- struct C.pthread_rwlock_t
- struct C.pthread_rwlockattr_t
- struct C.sem_t
- struct Channel
- struct ManyTimes
- struct Mutex
- struct Once
- struct RwMutex
- struct Semaphore
- struct WaitGroup