go语言中的互斥 + defer

互斥

互斥是传统的并发程序对共享资源进行访问控制的主要手段。它由标准库代码包sync中的Mutex结构体类型代表。sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开方法——Lock和Unlock。顾名思义,前者被用于锁定当前的互斥量,而后者则被用来对当前的互斥量进行解锁。

  • 包导入
import  "sync" //处理同步需求,导入包
  • 定义
    我们只需对它进行简单声明就可以正常使用了,就像这样:
var  mutex   = &sync.RWMutex{} //互斥定义
  • 使用
mutex.Lock()  // 上锁
defer mutex.Unlock() // 解锁,在defer后指定的函数会在函数退出前调用。
  • 比如在fabric v0.6 membersrvc/ca/ca.go中的代码片段:
// 通过证书hash值读取证书
func (ca *CA) readCertificateByHash(hash []byte) ([]byte, error) {
    caLogger.Debug("Reading certificate for hash " + string(hash) + ".")

    mutex.RLock()
    defer mutex.RUnlock()

    var raw []byte
    row := ca.db.QueryRow("SELECT cert FROM Certificates WHERE hash=?", hash)
    err := row.Scan(&raw) // scan将row中匹配的条目复制到raw指向的值。

    return raw, err
}

defer

在函数块中使用defer,相当于函数对应的栈空间,先进后出。函数结束后调用栈,进行defer操作。

golang的defer关键字,它可以在函数返回前执行一些操作,最常用的就是打开一个资源(例如一个文件、数据库连接等)时就用defer延迟关闭改资源,以免引起内存泄漏。

如下代码所示,我们一般写打开一个资源是这样操作的:

func ReadWrite() bool {
    file.Open("file")

    // to do something

    if failureX {
        file.Close()
        return false
    }

    if failureY {
        file.Close()
        return false
    }

    file.Close()
    return true
}

上面的代码有很多是重复的,go的defer有效解决了这个问题。使用它后,不但代码量减少了很多,而且程序变得更优雅:

func ReadWrite() bool {
    file.Open("file")
    defer file.Close()
    // to do something
    if failureX {
        return false
    }
    if failureY {
        return false
    }
    return true
}

示例代码:

package main

import "fmt"
import "time"

type User struct {
    username string
}

func (this *User) Close() {
    fmt.Println("\n", this.username, "Closed !!!")
}

func print(z int) {
    fmt.Println("print z = ", z)
}

func deferRet(x,y int) (int){
    z := 0
    defer print(z) // defer后面只能跟函数???
    z = x + y
    fmt.Println("deferRet z = ", z)
    return z + 50 
}

func main() {
    fmt.Println("print name:")
    u1 := &User{"jack"}
    defer u1.Close()
    u2 := &User{"lily"}
    defer u2.Close()

    time.Sleep(10 * time.Second)  // 实际上,线程Sleep的10秒,u1,和u2早就可以Close()了,但却需要依赖main()函数的结束,才能defer执行。

    fmt.Println("main Done !")

    // 函数中的defer
    res := deferRet(1,1)
    fmt.Println("main res = ", res)

    // 我们可以在官方的文档中看到defer的执行顺序是逆序的,也就是先进后出的顺序:
    // 打印结果是:4,3,2,1,0
    fmt.Printf("print i:")
    for i := 0; i < 5; i++ {
        defer fmt.Printf("%d ", i)
    }
    fmt.Println("")
}

运行程序$ go run deferTest.go ,运行结果:

print name: // 之后光标大概会闪烁10s,然后打印其他信息
main Done !
deferRet z =  2
print z =  0
main res =  52
print i:
4 3 2 1 0 
 lily Closed !!!

 jack Closed !!!

参考文章:
http://blog.csdn.net/eclipser1987/article/details/12089271
http://www.jb51.net/article/57335.htm

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值