无互斥

Alright, Go "experts". How would you write this code in idiomatic Go, aka without a mutex in next?

package main

import (
    "fmt"
)

func main() {
    done := make(chan int)
    x := 0
    for i := 0; i < 10; i++ {
        go func() {
            y := next(&x)
            fmt.Println(y)
            done <- 0
        }()
    }
    for i := 0; i < 10; i++ {
        <-done
    }
    fmt.Println(x)

}

var mutex = make(chan int, 1)

func next(p *int) int {
    mutex <- 0
    // critical section BEGIN
    x := *p
    *p++
    // critical section END
    <-mutex
    return x

}

Assume you can't have two goroutines in the critical section at the same time, or else bad things will happen.

My first guess is to have a separate goroutine to handle the state, but I can't figure out a way to match up inputs / outputs.

You would use an actual sync.Mutex:

var mutex sync.Mutex

func next(p *int) int {
    mutex.Lock()
    defer mutex.Unlock()
    x := *p
    *p++
    return x
}

Though you would probably also group the next functionality, state and sync.Mutex into a single struct.

Though there's no reason to do so in this case, since a Mutex is better suited for mutual exclusion around a single resource, you can use goroutines and channels to achieve the same effect

http://play.golang.org/p/RR4TQXf2ct

x := 0

var wg sync.WaitGroup
send := make(chan *int)
recv := make(chan int)

go func() {
    for i := range send {
        x := *i
        *i++
        recv <- x
    }
}()

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func() {
        defer wg.Done()
        send <- &x
        fmt.Println(<-recv)
    }()
}
wg.Wait()
fmt.Println(x)

As @favoretti mentioned, sync/atomic is a way to do it.

But, you have to use int32 or int64 rather than int (since int can be different sizes on different platforms).

Here's an example on Playground

package main

import (
    "fmt"
    "sync/atomic"
)

func main() {
    done := make(chan int)
    x := int64(0)
    for i := 0; i < 10; i++ {
        go func() {
            y := next(&x)
            fmt.Println(y)
            done <- 0
        }()
    }
    for i := 0; i < 10; i++ {
        <-done
    }
    fmt.Println(x)

}

func next(p *int64) int64 {
    return atomic.AddInt64(p, 1) - 1
}