sync包里的对象,大多是不能复制的
--------------------------------------------------------------------------------
锁
sync.Mutex的Lock()方法,是不能重入的
var mu sync.Mutex // 零值表示未被锁定的互斥量
mu.Lock()
defer mu.Unlock() // 对未锁定的锁进行Unlock,会导致panic
var mu sync.RWMutex // RWMutex的写锁,是Lock()和Unlock(),没有WLock()
mu.RLock()
defer mu.RUnlock()
--------------------------------------------------------------------------------
条件变量
cond := sync.NewCond(new(sync.Mutex)) // 条件变量关联某个锁
condition := 0
go func() { // 消费者
for {
cond.L.Lock() // 消费者开始消费时,锁住
for condition == 0 { cond.Wait() } // 如果没有可消费的值,则等待
condition-- // 消费
fmt.Printf("Consumer: %d\n", condition)
cond.Signal() // 唤醒一个生产者
cond.L.Unlock() // 解锁
}
}()
for { // 生产者
cond.L.Lock() // 生产者开始生产
for condition == 100 { cond.Wait() } // 当生产太多时,等待消费者消费
condition++ // 生产
fmt.Printf("Producer: %d\n", condition)
cond.Signal() // 通知消费者可以开始消费了
cond.L.Unlock() // 解锁
}
--------------------------------------------------------------------------------
原子操作
每种原子操作支持的类型都有限
加减 Add
newi32 := atomic.AddInt32(&i32, 3) // 加3,i32也会被修改
atomic.AddUint32(&ui32, ^uint32(-N-1)) // 对uint32类型加N,N是负常数,
比较并交换 CAS
for {
a := b
if atomic.CompareAndSwapInt32(&b, a, a+3) { break }
}
载入 Load
并发读变量时,可能读到错误的值,例如32位机器上对int64进行写入,可能读到改了一半的数据
a := atomic.LoadInt32(&b) // cpu不会执行其他针对此值的读写操作
存储 Store开头的一组函数,cpu不会执行其他针对此值的读写操作
交换 Swap开头的一组函数,设置新值,返回旧值
atomic.Value是结构体,有两个方法:Load和Store,可以原子地读写任意类型的值,
Load不接受参数,返回一个interface{}类型的结果,对没有Store过的atomic.Value执行Load,返回nil
Store接受一个interface{}类型的参数,没有返回值,不能传nil,若之前Store过值,那么后来Store的值必须与之前Store的值具有相同的类型
只执行一次
var once sync.Once
once.Do( func () { ... } )
sync.WaitGroup是结构体类型,用字节数组代表计数,其中4字节表示给定计数,另外4字节表示等待计数
var wg sync.WaitGroup // wg在wait()返回之后可以重用
wg.Add(3) // 增加给定计数3,可以传负数,但给定计数不能小于0
wg.Done() // 给定计数减1,同样不能减成负数,否则panic
当给定计数减为0时,会唤醒所有阻塞的goroutine,并将等待计数置为0
wg.wait() // 如果给定计数为0,则立即返回,否则阻塞,并把等待计数加1
// 可以有多个wait()调用,当计数为0时,多个wait()都将返回
sync.Pool
New字段
可被赋值为一个函数 func() interface{},该函数用于在Pool为空时生成一个对象,
生成的对象不会被放进Pool里,而是直接返回给调用Get方法的调用方
Get方法
用于从Pool里获取任意的一个interface{}类型的值,并将其从Pool里删除。
优先从本地P对应的私有池和共享池获取对象,其次从其他P的共享池偷一个对象
如果Pool为空,就调用New字段保存的函数来得到一个对象,
如果New没有被赋值为函数就返回nil
Put方法
用于把一个interface{}类型的值放入Pool中
垃圾回收时,Pool里的全部对象都会被移除
p := sync.Pool{
New : func() interface{} { return 0 },
}
a := p.Get().(int)
p.put(2)
--------------------------------------------------------------------------------