簡體   English   中英

如何檢測占用鎖的goroutine?

[英]How to detect the goroutine that occupies the lock?

我用Echo制作了一個 HTTP 服務器,並存儲數據使用storm和數據 model,如下所示:

項目1(桶)

device_type_1(桶)

device_1(千伏)

device_2(千伏)

device_type_2(桶)

device_1(千伏)

device_2(千伏)

項目2(桶)

...

除了更新數據庫,收到 HTTP 請求后還有一些其他事情要做,所以我使用這樣的事務:

tx, err := db.Begin(true)
if err != nil {
  return
}
defer tx.Rollback()

// for simplicity
projectBkt := tx.From("project1")
projectBkt.Save(&project)


// other things
.......


if err := tx.Commit(); err != nil {
  return
}

螺栓事務提交時鎖定等待的可能性很高,堆棧如下所示:

goroutine 53 [semacquire, 5 minutes]:
sync.runtime_SemacquireMutex(0xc000002560, 0x16a7f00, 0x0)
        C:/Go/src/runtime/sema.go:71 +0x4e
sync.(*RWMutex).Lock(0xc000002558)
        C:/Go/src/sync/rwmutex.go:103 +0xc0
go.etcd.io/bbolt.(*DB).mmap(0xc0000023c0, 0x20000, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:246 +0x65
go.etcd.io/bbolt.(*DB).allocate(0xc0000023c0, 0x1, 0x0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/db.go:846 +0x24b
go.etcd.io/bbolt.(*Tx).allocate(0xc000e98fc0, 0x1, 0x0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:454 +0x79
go.etcd.io/bbolt.(*node).spill(0xc0001539d0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/node.go:368 +0x3f0
go.etcd.io/bbolt.(*Bucket).spill(0xc0001cb740, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:541 +0x73a
go.etcd.io/bbolt.(*Bucket).spill(0xc000e98fd8, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/bucket.go:508 +0x64f
go.etcd.io/bbolt.(*Tx).Commit(0xc000e98fc0, 0x0, 0x0)
        D:/data/Go/pkg/mod/go.etcd.io/bbolt@v1.3.0/tx.go:163 +0x1bf
github.com/asdine/storm.(*node).Commit(0xc0001cb380, 0x0, 0x0)
        D:/data/Go/pkg/mod/github.com/asdine/storm@v2.1.2+incompatible/transaction.go:46 +0x5c
.....

問題是如何檢測占用鎖的 goroutine 以便檢查整個操作序列?

Goroutine 沒有外部 ID。

通過設計,鎖可以在一個 goroutine 中獲取並在另一個 goroutine 中釋放。 因此,如果一個鎖被持有,它不會Goroutine 持有:任何人都可以解鎖它,並且沒有 ID 可以記錄誰鎖定了它。

(因此,答案是僅使用提供的互斥鎖,您看不到誰在占用它。)

您可以實現自己的並發安全方式,只是一個例子
Output:

start id=1
start id=2
start id=3
start id=4

goroutine id=1
goroutine id=4
goroutine id=2
goroutine id=3
Who has lock: 2

示例代碼:

package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

type myID struct {
    lockerID int
}

func routine(my *myID, id int, wg *sync.WaitGroup) {
    fmt.Printf("goroutine id=%d\n", id)
    if who == id {
        my.lockerID = id
    }
    time.Sleep(100 * time.Millisecond) // do some job
    wg.Done()
}

func main() {
    rand.Seed(time.Now().Unix())
    who = rand.Intn(myall) + 1
    my := &myID{0} // 0 : no one has lock yet
    var wg sync.WaitGroup
    wg.Add(myall)
    for id := 1; id <= myall; id++ {
        fmt.Printf("start id=%d\n", id)
        go routine(my, id, &wg)
    }
    fmt.Println()
    time.Sleep(50 * time.Millisecond)
    id := my.lockerID
    wg.Wait()
    fmt.Println("Who has lock:", id)
}

const myall = 4

var who int


暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM