# Go 的一个 CAS 操作使用场景

if len(c) < n {
c <- something // 写入
}

const (
_CHAN_SIZE  = 10
_GUARD_SIZE = 10
)

var c chan interface{} = make(_CHAN_SIZE + _GUARD_SIZE) // 额外分配了一块保护的空间。

func write(val interface{}) {
if len(c) < _CHAN_SIZE {
c <- val
}
}

『弱弱的瞥一眼那个位置(操作)，没人占着咱就占，其他人占着咱也不等，直接走人』

// CompareAndSwapInt64 executes the compare-and-swap operation for an int64 value.
func CompareAndSwapInt64(addr *int64, old, new int64) (swapped bool)
...

，否则返回 false

func writeMsgWithCASCheck(val interface{}) {
if atomic.CompareAndSwapInt64(&flag, 0, 1) {
if len(c) < _CHAN_SIZE {
c <- val
atomic.StoreInt64(&obj.flag, 0)
return nil
}
atomic.StoreInt64(&obj.flag, 0)
}
}

func writeMsgWithCASCheck(val interface{}) {
for {
if atomic.CompareAndSwapInt64(&flag, 0, 1) {
if len(c) < _CHAN_SIZE {
...
}
}
}

$go run cas.go R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(2)+1 R(3)+1 R(1)+1 R(0)+1 R(1)+1 R(2)+1 R(3)+1 Chan overflow, len: 13. quit.$ go run cas.go cas
R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(0)+1 R(3)+1 R(1)+1 R(2)+1 R(1)+1 R(0)+1 R(3)+1 R(2)+1 R(1)+1 R(3)+1 R(3)+1 R(3)+1 R(3)+1 R(1)+1 R(2)+1 R(2)+1 R(2)+1 R(3)+1 R(1)+1 R(2)+1 R(3)+1 R(1)+1 R(1)+1 R(2)+1 R(1)+1 R(2)+1
quit.

package main

import (
"errors"
"fmt"
"os"
"sync/atomic"
"time"
)

const (
_CHAN_SIZE  = 10
_GUARD_SIZE = 10

_TEST_CNT = 32
)

type Obj struct {
flag int64
c    chan interface{}
}

func (obj *Obj) readLoop() error {
counter := _TEST_CNT
for {
time.Sleep(5 * time.Millisecond)
if len(obj.c) > _CHAN_SIZE {
return errors.New(fmt.Sprintf("Chan overflow, len: %v.", len(obj.c)))
} else if len(obj.c) > 0 {
<-obj.c
counter--
}
if counter <= 0 {
return nil
}
}
}

func (obj *Obj) writeMsg(idx int, v interface{}) (err error) {
for {
if len(obj.c) < _CHAN_SIZE {
obj.c <- v
fmt.Printf("R(%v)+1 ", idx)
return nil
}
}
}

func (obj *Obj) writeMsgWithCASCheck(idx int, v interface{}) (err error) {
for {
if atomic.CompareAndSwapInt64(&obj.flag, 0, 1) {
if len(obj.c) < _CHAN_SIZE {
obj.c  1 && os.Args[1] == "cas" {
useCAS = true
}
routineCnt := 4
tryCnt := _TEST_CNT / routineCnt
var obj = &Obj{c: make(chan interface{}, _CHAN_SIZE+_GUARD_SIZE)}

for idx := 0; idx < routineCnt; idx++ {
go func(nameIdx int) {
for tryIdx := 0; tryIdx < tryCnt; tryIdx++ {
if useCAS {
obj.writeMsgWithCASCheck(nameIdx, nil)
} else {
obj.writeMsg(nameIdx, nil)
}
}
}(idx)
}

}