-2

Getting deadlock somewhere. What is causing it and how should it be fixed? Trying to create a molecule creation. Function Make takes input as a string:

func testMolecule() {
    water := New()
    water.Make("HOH")   // water.Make("OOHHHH")
    fmt.Println(water.Molecules())
    // Output: 1
}

Function should return number of molecules created. Molecule should have 1 O-molecule and 2 H-molecule. Produce function shouldn't be done till all molecules are created.

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
}

1 Answers1

0

Function should return number of molecules created. Molecule should have 1 O-molecule and 2 H-molecule.

You don't need any synchronization or concurrency for that. Just count the Os, the Hs, and return the lesser of number of O or half number of H.

https://play.golang.org/p/3FaJDMi5ER7

I know from the previous question that you probably are trying to build some sort of simulation or model, but I don't understand your goals for that.

erik258
  • 14,701
  • 2
  • 25
  • 31
  • I'm trying to use synchronisation, cooperative synchronization and to try to implement using condition variables, i.e., sync.Cond. – Marsh Mellow Nov 08 '21 at 15:07