Documentation
¶
Overview ¶
Package boc is a Go implementation of paper "When Concurrency Matters: Behaviour-Oriented Concurrency" in OOPSLA2023.
- The core data structure is CownPtr, which is a pointer to a cown.
- The core primitive is When. Use When1, When2, When3, When4, WhenVec if possible to leverage generic and type checking.
- Use EnableTypeCheck or set "TYPE_CHECK=1" as environment variable can also enable type checking.
- TypeCheckHelper are used to skip some operations except When statements.
- TypeCheckWait is used to wait for all When statements(goroutines spawned) to finish.
This package is rewritten from boc.rs. The benchmark is provided by kaist-cp/cs431 and rewritten in Go.
Index ¶
- Variables
- func EnableTypeCheck()
- func TypeCheckHelper(fn func())
- func TypeCheckWait()
- func When(cowns CownIfaceVec, fn func(cowns CownIfaceVec))
- func When1[T any](cown CownPtr[T], fn func(*T), postFn func())
- func When2[T0, T1 any](cown0 CownPtr[T0], cown1 CownPtr[T1], fn func(*T0, *T1), postFn func())
- func When3[T0, T1, T2 any](cown0 CownPtr[T0], cown1 CownPtr[T1], cown2 CownPtr[T2], ...)
- func When4[T0, T1, T2, T3 any](cown0 CownPtr[T0], cown1 CownPtr[T1], cown2 CownPtr[T2], cown3 CownPtr[T3], ...)
- func WhenVec[T any](cowns CownPtrVec[T], fn func(content ...*T), postFn func())
- type CownIfaceVec
- type CownPtr
- type CownPtrVec
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultPostFn = func() {}
DefaultPostFn is a default post function that does nothing.
Functions ¶
func EnableTypeCheck ¶
func EnableTypeCheck()
EnableTypeCheck is a function to enable type checking. Pass "TYPE_CHECK=1" to the environment variable can also enable type checking.
func TypeCheckHelper ¶
func TypeCheckHelper(fn func())
Use TypeCheckHelper to skip other operations, remaining only When statements. See example of TypeCheckHelper for usage.
Example ¶
EnableTypeCheck()
c1 := NewCownPtr(1)
c2 := NewCownPtr(false)
t1 := CownIfaceVec{c1, c2}
ch := make(chan bool)
When(t1,
gen2(
func(g1 *bool, g2 *int) { // here g1, g2's type is wrong, should panic
TypeCheckHelper(func() {
*g1 = false
*g2 += 2
ch <- true
})
},
func() {
if r := recover(); r != nil {
if strings.HasPrefix(r.(error).Error(), "convertion from interface") {
fmt.Println(r)
return
}
}
panic("error is not interface convertion error")
},
),
)
TypeCheckHelper(func() {
<-ch
})
TypeCheckWait()
Output: convertion from interface{boc.CownPtr[int]} to boc.CownPtr[bool] failed
func TypeCheckWait ¶ added in v0.1.1
func TypeCheckWait()
Insert TypeCheckWait to the end of the main goroutine to wait for all When statements(goroutines spawned) to finish.
func When ¶
func When(cowns CownIfaceVec, fn func(cowns CownIfaceVec))
Use When1, When2, When3, When4 or WhenVec instead of When if possible to leverage compiler type checking. If you want to use When directly, you can use AsCownPtr in fn to convert each cown in cowns to the correct type.
Example ¶
c1 := NewCownPtr(0)
c2 := NewCownPtr(0)
c3 := NewCownPtr(false)
ch := make(chan bool)
When(CownIfaceVec{c1, c2}, func(cowns CownIfaceVec) {
x0 := AsCownPtr[int](cowns[0]).AddrOfValue() // dynamic type checking
x1 := AsCownPtr[int](cowns[1]).AddrOfValue()
*x0 += 1
*x1 += 1
fmt.Println(*x0, *x1)
When(CownIfaceVec{c3, c2}, func(cowns CownIfaceVec) {
g3 := AsCownPtr[bool](cowns[0]).AddrOfValue()
g2 := AsCownPtr[int](cowns[1]).AddrOfValue()
*g2 += 1
*g3 = true
fmt.Println(*g2, *g3)
ch <- true
})
})
<-ch
Output: 1 1 2 true
func When1 ¶
When1 is a helper function for When with one cown. postFn is a function that will be called after fn. It is useful for cleanup and handling panic in spawned goroutine.
See example of When2 and boc_test.go for usage.
See example of TypeCheckHelper for usage of postFn to handle panic.
func When2 ¶
When2 is a helper function for When with two cown. See When1 for further explanation.
Example ¶
c1 := NewCownPtr(1)
c2 := NewCownPtr(2)
c3 := NewCownPtr(false)
ch := make(chan int)
When2(c1, c2, func(g1 *int, g2 *int) {
*g1 += 1
*g2 += 2
When2(c2, c3, func(g2 *int, g3 *bool) {
*g2 += 1
*g3 = true
fmt.Println(*g1, *g2, *g3)
}, DefaultPostFn)
}, DefaultPostFn)
When3(c1, c2, c3, func(g1 *int, g2 *int, g3 *bool) {
if *g1 != 2 {
panic("g1 should be 2") // Attention! don't use t.Fatalf here
}
if *g2 != 4 {
panic("g2 should be 4")
}
ch <- 1
}, DefaultPostFn)
<-ch
Output: 2 5 true
func When3 ¶
func When3[T0, T1, T2 any](cown0 CownPtr[T0], cown1 CownPtr[T1], cown2 CownPtr[T2], fn func(*T0, *T1, *T2), postFn func())
See When1 for further explanation.
func When4 ¶
func When4[T0, T1, T2, T3 any](cown0 CownPtr[T0], cown1 CownPtr[T1], cown2 CownPtr[T2], cown3 CownPtr[T3], fn func(*T0, *T1, *T2, *T3), postFn func())
See When1 for further explanation.
func WhenVec ¶
func WhenVec[T any](cowns CownPtrVec[T], fn func(content ...*T), postFn func())
WhenVec is a helper function for a slice of cowns with same type. See When1 for further explanation.
Example ¶
c1 := NewCownPtr(0)
c2 := NewCownPtr(0)
c3 := NewCownPtr(false)
ch := make(chan bool)
WhenVec(CownPtrVec[int]{c1, c2}, func(x ...*int) {
*x[0] += 1
*x[1] += 1
When2(c3, c2, func(g3 *bool, g2 *int) {
*g2 += 1
*g3 = true
fmt.Println(*x[0], *x[1], *g3)
ch <- true
}, DefaultPostFn)
}, DefaultPostFn)
<-ch
Output: 1 2 true
Types ¶
type CownIfaceVec ¶
type CownIfaceVec []cownIface
CownIfaceVec is a slice of cownIface. cownIface can store different types of CownPtr[T]. The use case is CownIfaceVec{CownPtr[int], CownPtr[bool], ...}. But the type checking have to be deferred to runtime.
If macro is supported, finite tuple type (CownPtr[int], (CownPtr[bool], ...) can replace this
type CownPtr ¶
type CownPtr[T any] struct { // contains filtered or unexported fields }
CownPtr is a wrapper for a cown[T].
Use NewCownPtr to create a new CownPtr. User should not care about the inner data.
func NewCownPtr ¶
NewCownPtr creates a new CownPtr with the given value. The value is stored in a cown, which allows for safe concurrent access. The CownPtr can be used to pass the value to other goroutines safely.
func (CownPtr[T]) AddrOfValue ¶
func (ptr CownPtr[T]) AddrOfValue() *T
CownPtr.AddrOfValue returns the address of the value inside the CownPtr. This is useful for passing the value to a function that requires a pointer.
type CownPtrVec ¶
CownPtrVec is a slice of CownPtr with same type parameter T. Use CownPtrVec.ToIfaceVec to convert it to CownIfaceVec.
func (CownPtrVec[T]) ToIfaceVec ¶ added in v0.1.1
func (slice CownPtrVec[T]) ToIfaceVec() CownIfaceVec
CownPtrVec.ToIfaceVec converts a slice of CownPtr[T] to CownIfaceVec. This is useful for passing a slice of CownPtr[T] to a function that expects a CownIfaceVec.