Go 竞争检测器在使用互斥锁时报告竞争条件并反射(reflect)被锁定的结构,示例代码如下。即使通过锁定互斥锁来保护对结构成员的反射和访问,竞争检测器仍然报告竞争条件。
我该如何解决争用?
代码:

// main file
package main

import (
    "fmt"
    "reflect"
    "sync"
)

type TestType struct {
    counter uint64
    lock sync.Mutex
}

func NewTestType() *TestType {
    t := &TestType{
        counter: 0,
        lock:    sync.Mutex{},
    }

    go func() {
        t.lock.Lock()
        defer t.lock.Unlock()
        t.counter++
    }()

    return t
}

func ItShouldNotRace() string {
    t := NewTestType()

    t.lock.Lock()
    defer t.lock.Unlock()

    val := reflect.ValueOf(t)
    iface := val.Interface()
    return fmt.Sprintf("%v", iface)
}

// test file
package main

import (
    "testing"
)

func TestItShouldNotRace(t *testing.T) {
    if ItShouldNotRace() == "impossible" {
        t.Fail()
    }
}
种族检测器输出:
==================
WARNING: DATA RACE
Read at 0x00c000120078 by goroutine 7:
  reflect.typedmemmove()
      /usr/local/opt/go/libexec/src/runtime/mbarrier.go:177 +0x0
  reflect.packEface()
      /usr/local/opt/go/libexec/src/reflect/value.go:120 +0x12f
  reflect.valueInterface()
      /usr/local/opt/go/libexec/src/reflect/value.go:1045 +0x1cd
  reflect.Value.Interface()
      /usr/local/opt/go/libexec/src/reflect/value.go:1015 +0x3aa4
  fmt.(*pp).printValue()
      /usr/local/opt/go/libexec/src/fmt/print.go:726 +0x3aa5
  fmt.(*pp).printValue()
      /usr/local/opt/go/libexec/src/fmt/print.go:880 +0x25fc
  fmt.(*pp).printArg()
      /usr/local/opt/go/libexec/src/fmt/print.go:716 +0x26b
  fmt.(*pp).doPrintf()
      /usr/local/opt/go/libexec/src/fmt/print.go:1030 +0x326
  fmt.Sprintf()
      /usr/local/opt/go/libexec/src/fmt/print.go:219 +0x73
  go_issue.ItShouldNotRace()
      /Users/dedalus/Downloads/go_issue/main.go:37 +0x1a4
  go_issue.TestItShouldNotRace()
      /Users/dedalus/Downloads/go_issue/main_test.go:8 +0x2f
  testing.tRunner()
      /usr/local/opt/go/libexec/src/testing/testing.go:1127 +0x202

Previous write at 0x00c000120078 by goroutine 8:
  sync/atomic.CompareAndSwapInt32()
      /usr/local/opt/go/libexec/src/runtime/race_amd64.s:293 +0xb
  sync.(*Mutex).lockSlow()
      /usr/local/opt/go/libexec/src/sync/mutex.go:129 +0x14b
  sync.(*Mutex).Lock()
      /usr/local/opt/go/libexec/src/sync/mutex.go:81 +0x84
  go_issue.NewTestType.func1()
      /Users/dedalus/Downloads/go_issue/main.go:21 +0x47

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/local/opt/go/libexec/src/testing/testing.go:1178 +0x796
  testing.runTests.func1()
      /usr/local/opt/go/libexec/src/testing/testing.go:1449 +0xa6
  testing.tRunner()
      /usr/local/opt/go/libexec/src/testing/testing.go:1127 +0x202
  testing.runTests()
      /usr/local/opt/go/libexec/src/testing/testing.go:1447 +0x5aa
  testing.(*M).Run()
      /usr/local/opt/go/libexec/src/testing/testing.go:1357 +0x4eb
  main.main()
      _testmain.go:43 +0x236

Goroutine 8 (running) created at:
  go_issue.NewTestType()
      /Users/dedalus/Downloads/go_issue/main.go:20 +0x7a
  go_issue.ItShouldNotRace()
      /Users/dedalus/Downloads/go_issue/main.go:30 +0x54
  go_issue.TestItShouldNotRace()
      /Users/dedalus/Downloads/go_issue/main_test.go:8 +0x2f
  testing.tRunner()
      /usr/local/opt/go/libexec/src/testing/testing.go:1127 +0x202
==================
--- FAIL: TestItShouldNotRace (0.00s)
    testing.go:1042: race detected during execution of test

最佳答案

这种数据竞争可以通过使 lock 成为一个指针来解决:

type TestType struct {
    counter uint64
    lock *sync.Mutex
}
来自 sync.Mutex 文档:
// A Mutex must not be copied after first use.
lock 字段使用值类型会导致复制此互斥锁。

关于go - 使用互斥锁和反射时的竞争条件,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64735267/

10-09 15:32