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/