I'm new to golang and I just wish to print out 10 alphanumeric numbers combining elements from numeber-range and character-range.
I decided to do it concurrently, but I've been running into an error regarding deadlock.
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
type alphanumeric struct {
anAlphabet string
aNumber string
}
func (someStruct alphanumeric) pairAlphanumeric() string {
return someStruct.aNumber + someStruct.anAlphabet
}
func main() {
var wg sync.WaitGroup
numbers := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
alphabets := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
//var aleph alphanumeric
//var alephS []alphanumeric
wg.Add(len(alphabets))
go func(numbers []string, alphabets []string) {
defer wg.Done()
for i := 0; i < 10; i++ {
makeAleph(numbers, alphabets)
}
}(numbers, alphabets)
wg.Wait()
} // end of main()
func makeAleph(numbers []string, alphabets []string) {
var aleph alphanumeric
aleph.anAlphabet = aNum(numbers)
aleph.aNumber = anAlph(alphabets)
fmt.Println(aleph.pairAlphanumeric())
//return aleph.pairAlphanumeric()
}
func randomIndex() int {
randTime := time.Time.UnixNano(time.Now())
rand.Seed(randTime)
return rand.Intn(10)
}
func aNum(numbers []string) string {
return numbers[randomIndex()]
}
func anAlph(alphabets []string) string {
return alphabets[randomIndex()]
}
And the error that it throws after printing the required numbers correctly is:
❯ go run aleph.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_Semacquire(0xc42000e2dc)
/Users/eklavya/.gvm/gos/go1.8/src/runtime/sema.go:47 +0x34
sync.(*WaitGroup).Wait(0xc42000e2d0)
/Users/eklavya/.gvm/gos/go1.8/src/sync/waitgroup.go:131 +0x7a
main.main()
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:38 +0x14c
goroutine 5 [chan receive (nil chan)]:
main.makeAleph(0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:61 +0x134
main.main.func1(0xc42000e2d0, 0xc420084000, 0xa, 0xa, 0xc420001520, 0x1a, 0x1a)
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:35 +0x94
created by main.main
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:37 +0x13e
goroutine 6 [chan send (nil chan)]:
main.aNum(0x0, 0xc420084000, 0xa, 0xa)
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:79 +0x5b
main.makeAleph.func1(0xc42000e2e0, 0x0, 0xc420084000, 0xa, 0xa)
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:51 +0x73
created by main.makeAleph
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:52 +0xad
goroutine 7 [chan send (nil chan)]:
main.anAlph(0x0, 0xc420001520, 0x1a, 0x1a)
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:85 +0x5b
main.makeAleph.func2(0xc42000e2e0, 0x0, 0xc420001520, 0x1a, 0x1a)
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:56 +0x73
created by main.makeAleph
/Users/eklavya/Projects/Polyglot/TedTalks/goTED/experiments/async/aleph.go:57 +0xff
exit status 2
How can I avoid deadlock in printing alphanumeric numbers concurrently?
Your current code is not concurrent at all. All the alphanumeric codes are generated sequentially in a single for
loop running in the sole goroutine you are creating besides main
.
You are adding len(alphabets) == 26
to wg.Wait
. That means you need to call 26 wg.Done
for the call to wg.Wait
to complete. Each wg.Done
call reduces the waitgroup counter by one.
In your code, you are calling wg.Done
only once. That means waitgroup counter stays at 25 once your goroutine returns and the call to wg.Wait
would never return since no other goroutine is running that may reduce the waitgroup counter by making further calls to wg.Done
.
To (vaguely) get what you want, you can try something like this:
// ...
n := 10 // number of codes you want to print
wg.Add(n)
for i := 0; i < n; i++ {
go func(numbers []string, alphabets []string) {
defer wg.Done()
makeAleph(numbers, alphabets)
}(numbers, alphabets)
wg.Wait()
// ...
Now, n
goroutines will be spawned, each responsible for printing one code by calling makeAleph
. As soon as a goroutine returns, wg.Done
is called. A total n
wg.Done
s are called allowing call to wg.Wait
in main
to complete.