golang使用sync保证container/list链表线程安全

一边python,一边golang ! 时常因为工作切换语言造成了短路。container/list是golang语言内置的链表库。 对比其他语言的list,container/list该有的功能都有,就缺一个popLeft popRight方法。如果要实现pop方法需要去除value := list.Back() , 然后list.Remove(value) 。但这样不能保持操作的原子性。 解决的方法是用全局的互斥锁。 

该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。

http://xiaorui.cc/?p=2923


下面是 container/list 包的基本用法.

#xiaorui.cc

func (e *Element) Next() *Element  //返回该元素的下一个元素,如果没有下一个元素则返回nil
func (e *Element) Prev() *Element//返回该元素的前一个元素,如果没有前一个元素则返回nil。
func New() *List //返回一个初始化的list
func (l *List) Back() *Element //获取list l的最后一个元素
func (l *List) Front() *Element //获取list l的第一个元素
func (l *List) Init() *List  //list l初始化或者清除list l
func (l *List) InsertAfter(v interface{}, mark *Element) *Element  //在list l中元素mark之后插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。
func (l *List) InsertBefore(v interface{}, mark *Element) *Element//在list l中元素mark之前插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。
func (l *List) Len() int //获取list l的长度
func (l *List) MoveAfter(e, mark *Element)  //将元素e移动到元素mark之后,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。
func (l *List) MoveBefore(e, mark *Element)//将元素e移动到元素mark之前,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。
func (l *List) MoveToBack(e *Element)//将元素e移动到list l的末尾,如果e不属于list l,则list不改变。
func (l *List) MoveToFront(e *Element)//将元素e移动到list l的首部,如果e不属于list l,则list不改变。
func (l *List) PushBack(v interface{}) *Element//在list l的末尾插入值为v的元素,并返回该元素。
func (l *List) PushBackList(other *List)//在list l的尾部插入另外一个list,其中l和other可以相等。
func (l *List) PushFront(v interface{}) *Element//在list l的首部插入值为v的元素,并返回该元素。
func (l *List) PushFrontList(other *List)//在list l的首部插入另外一个list,其中l和other可以相等。
func (l *List) Remove(e *Element) interface{}//如果元素e属于list l,将其从list中删除,并返回元素e的值。

需要说明的是,container/list默认不是线程安全的,应该说大多数语言自带的list都不能确保数据安全。 如果你想保证数据安全,那么可以使用Lock锁解决。 

#xiaorui.cc
package main

import (
    "container/list"
    "fmt"
)

func main() {
    // 生成队列
    l := list.New()
    // 入队, 压栈
    l.PushBack(1)
    l.PushBack(2)
    l.PushBack(3)
    l.PushBack(4)
    // 出队
    v1 := l.Front()
    l.Remove(v1)
    fmt.Printf("%d\n", v1.Value)
    // 出栈
    a1 := l.Back()
    l.Remove(a1)
    fmt.Printf("%d\n", a1.Value)
}


如果你是在goroutine协程环境下使用container/list链表,那么一定要记得加锁。  代码如下:

#xiaorui.cc
#xiaorui.cc
package main  
  
import (  
    "fmt"  
    "sync"  
)  
  
func main() {  
    var l *sync.Mutex  
    l = new(sync.Mutex)  
    l.Lock()  
    defer l.Unlock()  
    fmt.Println("1")  
}  


使用container/list包结合sync的mutex互斥锁造了一个支持线程安全的链表。 

package main

import (
    "container/list"
    "fmt"
    "sync"
    "time"
)

type Queue struct {
    data *list.List
}

func NewQueue() *Queue {
    q := new(Queue)
    q.data = list.New()
    return q
}

func (q *Queue) push(v interface{}) {
    defer lock.Unlock()
    lock.Lock()
    q.data.PushFront(v)
}

func (q *Queue) pop() interface{} {
    defer lock.Unlock()
    lock.Lock()
    iter := q.data.Back()
    v := iter.Value
    q.data.Remove(iter)
    return v
}

func (q *Queue) dump() {
    for iter := q.data.Back(); iter != nil; iter = iter.Prev() {
        fmt.Println("item:", iter.Value)
    }
}

var lock sync.Mutex

func main() {
    q := NewQueue()
    go func() {
        q.push("one")
    }()
    go func() {
        q.push("four")
    }()
    q.push("two")
    q.push("three")
    v := q.pop()
    fmt.Println("pop v:", v)
    fmt.Println("......")
    time.Sleep(1 * time.Second)
    q.dump()
}

上面那段go代码运行后的结果:

pop v: two
......
item: three
item: one
item: four

参考学习:
    http://blog.csdn.net/chenbaoke/article/details/42780895


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

发表评论

邮箱地址不会被公开。 必填项已用*标注