在某处陷入僵局。是什么原因造成的,应该如何解决?试图创造一个分子创造。函数 Make 将输入作为字符串:
func testMolecule() {
water := New()
water.Make("HOH") // water.Make("OOHHHH")
fmt.Println(water.Molecules())
// Output: 1
}
函数应返回创建的分子数。分子应该有 1 个 O 分子和 2 个 H 分子。在创建所有分子之前不应完成生产功能。
import (
"sync"
)
// Water structure holds the synchronization primitives and
// data required to solve the water molecule problem.
// moleculeCount holds the number of molecules formed so far.
// result string contains the sequence of "H" and "O".
// wg WaitGroup is used to wait for goroutine completion.
type Water struct {
sync.Mutex
wg sync.WaitGroup
cond *sync.Cond
moleculeCount int
result string
assignedO int
assignedH int
finished bool
}
// New initializes the water structure.
func New() *Water {
water := &Water{
moleculeCount: 0,
result: "",
assignedO: 0,
assignedH: 0,
finished: false,
}
water.cond = sync.NewCond(water)
return water
}
// releaseOxygen produces one oxygen atom if no oxygen atom is already present.
// If an oxygen atom is already present, it will block until enough hydrogen
// atoms have been produced to consume the atoms necessary to produce water.
//
// The w.wg.Done() must be called to indicate the completion of the goroutine.
func (w *Water) releaseOxygen() {
defer w.wg.Done()
for {
w.Lock()
if w.assignedO == 0 {
w.assignedO = 1
}
for !(w.assignedH == 2) {
w.cond.Wait()
}
w.result = w.result + "O"
w.cond.Broadcast()
w.Unlock()
}
}
// releaseHydrogen produces one hydrogen atom unless two hydrogen atoms are already present.
// If two hydrogen atoms are already present, it will block until another oxygen
// atom has been produced to consume the atoms necessary to produce water.
//
// The w.wg.Done() must be called to indicate the completion of the goroutine.
func (w *Water) releaseHydrogen() {
defer w.wg.Done()
for {
w.Lock()
if w.assignedH < 2 {
w.assignedH = w.assignedH + 1
}
for !(w.assignedO == 1) && w.assignedH == 2 {
w.cond.Wait()
}
w.result = w.result + "HH"
w.cond.Broadcast()
w.Unlock()
}
}
// produceMolecule forms the water molecules.
func (w *Water) produceMolecule(done chan bool) {
for {
w.Lock()
for w.assignedO == 1 && w.assignedH == 2 && !w.finished {
w.cond.Wait()
}
if w.assignedO == 0 && w.assignedH == 0 && w.finished {
w.Unlock()
break
}
w.moleculeCount = w.moleculeCount + 1
w.assignedH = 0
w.assignedO = 0
w.cond.Broadcast()
w.Unlock()
}
done <- true
}
func (w *Water) finish() {
w.Lock()
w.finished = true
w.cond.Broadcast()
w.Unlock()
}
func (w *Water) Molecules() int {
return w.moleculeCount
}
// Make returns a sequence of water molecules derived from the input of hydrogen and oxygen atoms.
func (w *Water) Make(input string) string {
done := make(chan bool)
go w.produceMolecule(done)
for _, ch := range input {
w.wg.Add(1)
switch ch {
case 'O':
go w.releaseOxygen()
case 'H':
go w.releaseHydrogen()
}
}
w.wg.Wait()
w.finish()
<-done
return w.result
}