Ensure that a series of executions have the properties of:
- Exclusivity: One at a time execution
- Order: Execution happens in first in, first out (FIFO) order
serial.Executor provides these guarantees. Given a serialize.Executor executor
:
executor.AsyncExec(func(){...})
will non-blockingly add func(){...}
to an ordered queue (first in, first out (FIFO)) to be executed.
executor.AsyncExec(func(){...}
returns a channel that will be closed when func() has returned. Therefore:
<-executor.AsyncExec(func(){...})
will add func(){...}
to an ordered queue (first in, first out (FIFO)) to be executed and return when
func(){...}
has returned.
sync.Mutex
guarantees exclusivity, but not order. For this reason it is often used synchronously to ensure ordering.
serialize.Executor
guarantees both exclusivity and order, allowing asynchronous use.
serial.Executor.Exec can be used in situations in which you need thread safe modification of an object but don't need to or want to block waiting for it to happen:
type myStruct struct {
data string
executor serialize.Executor
}
func (m *myStruct) Update(s string) {
m.executor.AsyncExec(func(){
m.data = s
})
}
serialize.Executor.Exec can also be in situations in which you need thread safe modification of an object but need Synchronous update.
type myStruct struct {
data string
executor serialize.Executor
}
func (m *myStruct) Update(s string) {
<-m.executor.AsyncExec(func(){
m.data = s
})
}
serialize.Executor is pretty resistant to most classes of deadlock mistakes. You can nest calls to AsyncExec as far down as you'd like:
func nested(executor *serialize.Executor) {
executor.AsyncExec(func(){
executor.AsyncExec(func(){
executor.AsyncExec(func(){
}
}
})
}
will not deadlock no matter how far down you nest.
However, care must be taken to not nest calls to AsyncExec if you block on the returned done channel.
func deadlockNested(executor *serialize.Executor) {
executor.AsyncExec(func(){
<-executor.AsyncExec(func(){
}
}
}
will deadlock 100% of the time. Do not block on done channels in nested calls to AsyncExec