《go语言程序设计》学习(九)

一,线程安全的类

package safeslice

type safeSlice chan commandData

type commandData struct {
    action  commandAction
    index   int
    item    interface{}
    result  chan<- interface{}
    data    chan<- []interface{}
    updater UpdateFunc
}

type commandAction int

const (
    insert commandAction = iota
    remove
    at
    update
    end
    length
)

type UpdateFunc func(interface{}) interface{}

type SafeSlice interface {
    Append(interface{})     // Append the given item to the slice
    At(int) interface{}     // Return the item at the given index position
    Close() []interface{}   // Close the channel and return the slice
    Delete(int)             // Delete the item at the given index position
    Len() int               // Return the number of items in the slice
    Update(int, UpdateFunc) // Update the item at the given index position
}

func New() SafeSlice {
    slice := make(safeSlice)
    go slice.run()
    return slice
}

func (slice safeSlice) run() {
    list := make([]interface{}, 0)
    for command := range slice {
        switch command.action {
        case insert:
            list = append(list, command.item)
        case remove: // potentially expensive for long lists
            if 0 <= command.index && command.index < len(list) {
                list = append(list[:command.index],
                    list[command.index+1:]...)
            }
        case at:
            if 0 <= command.index && command.index < len(list) {
                command.result <- list[command.index]
            } else {
                command.result <- nil
            }
        case length:
            command.result <- len(list)
        case update:
            if 0 <= command.index && command.index < len(list) {
                list[command.index] = command.updater(list[command.index])
            }
        case end:
            close(slice)
            command.data <- list
        }
    }
}

func (slice safeSlice) Append(item interface{}) {
    slice <- commandData{action: insert, item: item}
}

func (slice safeSlice) Delete(index int) {
    slice <- commandData{action: remove, index: index}
}

func (slice safeSlice) At(index int) interface{} {
    reply := make(chan interface{})
    slice <- commandData{at, index, nil, reply, nil, nil}
    return <-reply
}

func (slice safeSlice) Len() int {
    reply := make(chan interface{})
    slice <- commandData{action: length, result: reply}
    return (<-reply).(int)
}

// If the updater calls a safeSlice method we will get deadlock!
func (slice safeSlice) Update(index int, updater UpdateFunc) {
    slice <- commandData{action: update, index: index, updater: updater}
}

func (slice safeSlice) Close() []interface{} {
    reply := make(chan []interface{})
    slice <- commandData{action: end, data: reply}
    return <-reply
}

这是一个线程安全的slice,表面上看,看不到任何锁或者互斥量等任何操作来实现线程安全。

实际上,着应该说,说一个披着slice外衣的actor。。

整个实现说这样:启动一个gorountin,并给它一个channel,当需要操作这个slice点时候,就把希望操作的信息封装进command这个struct内,然后把整个struct打包,从这个channel发送到gorountin,然后这个“slice”有序的从gorountin读取到这个command,就按照command的操作信息,把command操作执行。

如果gorountin没有缓冲区,那么所有多操作都是阻塞的,也就是说,如果1-5这5个线程按顺序的都要操作这个slice,那么,在第一个请求执行完之前,其他线程的请求都时挂起的,直到第一个执行完,按顺序执行第二个。

原文地址:https://www.cnblogs.com/mruoli/p/4709382.html