golang标准库 sync

    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)




    --------------------------------------------------------------------------------

猜你喜欢

转载自www.cnblogs.com/ts65214/p/12976197.html