mirror of
https://github.com/golang/go
synced 2024-11-12 05:30:21 -07:00
runtime/race: more precise handling of channel synchronization
It turns out there is a relatively common pattern that relies on inverted channel semaphore: gate := make(chan bool, N) for ... { // limit concurrency gate <- true go func() { foo(...) <-gate }() } // join all goroutines for i := 0; i < N; i++ { gate <- true } So handle synchronization on inverted semaphores with cap>1. Fixes #7718. LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/84880046
This commit is contained in:
parent
f4ecfaa442
commit
9e1cadad0f
@ -172,8 +172,7 @@ asynch:
|
||||
}
|
||||
|
||||
if(raceenabled) {
|
||||
if(c->dataqsiz == 1)
|
||||
runtime·raceacquire(chanbuf(c, c->sendx));
|
||||
runtime·raceacquire(chanbuf(c, c->sendx));
|
||||
runtime·racerelease(chanbuf(c, c->sendx));
|
||||
}
|
||||
|
||||
@ -304,8 +303,7 @@ asynch:
|
||||
|
||||
if(raceenabled) {
|
||||
runtime·raceacquire(chanbuf(c, c->recvx));
|
||||
if(c->dataqsiz == 1)
|
||||
runtime·racerelease(chanbuf(c, c->recvx));
|
||||
runtime·racerelease(chanbuf(c, c->recvx));
|
||||
}
|
||||
|
||||
if(ep != nil)
|
||||
@ -855,8 +853,7 @@ asyncrecv:
|
||||
if(cas->sg.elem != nil)
|
||||
runtime·racewriteobjectpc(cas->sg.elem, c->elemtype, cas->pc, chanrecv);
|
||||
runtime·raceacquire(chanbuf(c, c->recvx));
|
||||
if(c->dataqsiz == 1)
|
||||
runtime·racerelease(chanbuf(c, c->recvx));
|
||||
runtime·racerelease(chanbuf(c, c->recvx));
|
||||
}
|
||||
if(cas->receivedp != nil)
|
||||
*cas->receivedp = true;
|
||||
@ -881,8 +878,7 @@ asyncrecv:
|
||||
asyncsend:
|
||||
// can send to buffer
|
||||
if(raceenabled) {
|
||||
if(c->dataqsiz == 1)
|
||||
runtime·raceacquire(chanbuf(c, c->sendx));
|
||||
runtime·raceacquire(chanbuf(c, c->sendx));
|
||||
runtime·racerelease(chanbuf(c, c->sendx));
|
||||
runtime·racereadobjectpc(cas->sg.elem, c->elemtype, cas->pc, chansend);
|
||||
}
|
||||
|
41
src/pkg/runtime/race/testdata/chan_test.go
vendored
41
src/pkg/runtime/race/testdata/chan_test.go
vendored
@ -567,22 +567,6 @@ func TestRaceChanCloseLen(t *testing.T) {
|
||||
v = 2
|
||||
}
|
||||
|
||||
func TestRaceChanSameCell(t *testing.T) {
|
||||
c := make(chan int, 2)
|
||||
v := 0
|
||||
go func() {
|
||||
v = 1
|
||||
c <- 42
|
||||
<-c
|
||||
c <- 42
|
||||
<-c
|
||||
}()
|
||||
time.Sleep(1e7)
|
||||
c <- 43
|
||||
<-c
|
||||
_ = v
|
||||
}
|
||||
|
||||
func TestRaceChanCloseSend(t *testing.T) {
|
||||
compl := make(chan bool, 1)
|
||||
c := make(chan int, 10)
|
||||
@ -641,16 +625,35 @@ func TestNoRaceSelectMutex(t *testing.T) {
|
||||
|
||||
func TestRaceChanSem(t *testing.T) {
|
||||
done := make(chan struct{})
|
||||
mtx := make(chan struct{}, 2)
|
||||
mtx := make(chan bool, 2)
|
||||
data := 0
|
||||
go func() {
|
||||
mtx <- struct{}{}
|
||||
mtx <- true
|
||||
data = 42
|
||||
<-mtx
|
||||
done <- struct{}{}
|
||||
}()
|
||||
mtx <- struct{}{}
|
||||
mtx <- true
|
||||
data = 43
|
||||
<-mtx
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestNoRaceChanWaitGroup(t *testing.T) {
|
||||
const N = 10
|
||||
chanWg := make(chan bool, N/2)
|
||||
data := make([]int, N)
|
||||
for i := 0; i < N; i++ {
|
||||
chanWg <- true
|
||||
go func(i int) {
|
||||
data[i] = 42
|
||||
<-chanWg
|
||||
}(i)
|
||||
}
|
||||
for i := 0; i < cap(chanWg); i++ {
|
||||
chanWg <- true
|
||||
}
|
||||
for i := 0; i < N; i++ {
|
||||
_ = data[i]
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user