I'm trying to figure out why I have a dead lock with waitgroup.Wait()
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
defer wg.Done()
c <- i
}
func main() {
ch := make(chan int)
for i := 0; i < 10; i++ {
wg.Add(1)
go foo(ch, i)
}
wg.Wait()
close(ch)
for item := range ch {
fmt.Println(item)
}
}
When I run it like this, it prints fatal error: all goroutines are asleep - deadlock!
I tried to change ch to a buffered channel and that solved the problem. But I really want to know why is there a dead lock.
I've commented out the parts where your program's logic is not correct:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
defer wg.Done()
c <- i
}
func main() {
ch := make(chan int) // unbuffered channel
for i := 0; i < 10; i++ {
wg.Add(1)
go foo(ch, i)
}
// wg.Wait is waiting for all goroutines to finish but that's
// only possible if the send to channel succeeds. In this case,
// it is not possible as your receiver "for item := range ch" is below
// this. Hence, a deadlock.
wg.Wait()
// Ideally, it should be the sender's duty to close the channel.
// And closing a channel before the receiver where the channel
// is unbuffered is not correct.
close(ch)
for item := range ch {
fmt.Println(item)
}
}
Corrected program:
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func foo(c chan int, i int) {
defer wg.Done()
c <- i
}
func main() {
ch := make(chan int)
go func() {
for item := range ch {
fmt.Println(item)
}
}()
for i := 0; i < 10; i++ {
wg.Add(1)
go foo(ch, i)
}
wg.Wait()
close(ch)
}
Related
My task is to sync 2 goroutines so the output should look like that:
foobarfoobarfoobarfoobar
.The issue is that when I call them they come out completely randomized. This is my code:
package main
import (
"fmt"
"sync"
"time"
)
type ConcurrentPrinter struct {
sync.WaitGroup
sync.Mutex
}
func (cp *ConcurrentPrinter) printFoo(times int) {
cp.WaitGroup.Add(times)
go func() {
cp.Lock()
fmt.Print("foo")
cp.Unlock()
}()
}
func (cp *ConcurrentPrinter) printBar(times int) {
cp.WaitGroup.Add(times)
go func() {
cp.Lock()
fmt.Print("bar")
cp.Unlock()
}()
}
func main() {
times := 10
cp := &ConcurrentPrinter{}
for i := 0; i <= times; i++ {
cp.printFoo(i)
cp.printBar(i)
}
time.Sleep(10 * time.Millisecond)
}
As outlined in the comments, using goroutines may not be the best use case for what you are trying to achieve - and thus this may be an XY problem.
Having said that, if you want to ensure two independent goroutines interleave their work in an alternating sequence, you can implement a set of "ping-pong" mutexs:
var ping, pong sync.Mutex
pong.Lock() // ensure the 2nd goroutine waits & the 1st goes first
go func() {
for {
ping.Lock()
foo()
pong.Unlock()
}
}()
go func() {
for {
pong.Lock()
bar()
ping.Unlock()
}
}()
https://go.dev/play/p/VO2LoMJ8fek
Using channel:
func printFoo(i int, ch chan<- bool, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Print("foo")
ch <- true
}()
}
func printBar(i int, ch chan<- bool, wg *sync.WaitGroup) {
wg.Add(1)
go func() {
defer wg.Done()
fmt.Print("bar")
ch <- true
}()
}
func main() {
times := 4
firstchan := make(chan bool)
secondchan := make(chan bool)
var wg sync.WaitGroup
for i := 0; i <= times; i++ {
printFoo(i, firstchan, &wg)
<-firstchan
printBar(i, secondchan, &wg)
<-secondchan
}
wg.Wait()
}
https://go.dev/play/p/MlZ9dHkUXGb
The code given below is the sample code for my use case. I want to read data from ch1 and ch2 but got stuck into infinite loop.
package main
import "fmt"
func main() {
ch1, ch2 := func() (<-chan int, <-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
go worker_1(ch_1, ch_2)
go worker_2(ch_1, ch_2)
return ch_1, ch_2
}()
// trying to read this way but it is not working
for {
select {
case a := <-ch1:
fmt.Println("from ch1", a)
case a := <-ch2:
fmt.Println("from ch2", a)
default:
fmt.Println("done")
}
}
}
func worker_1(ch1, ch2 chan int) {
for i := 0; i < 100; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
func worker_2(ch1, ch2 chan int) {
for i := 101; i < 200; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
Here is one solution:
package main
import (
"fmt"
"sync"
)
func main() {
// Create channels
ch1, ch2 := make(chan int), make(chan int)
// Create workers waitgroup with a counter of 2
wgWorkers := sync.WaitGroup{}
wgWorkers.Add(2)
// Run workers
go worker(&wgWorkers, ch1, ch2, 0, 100) // Worker 1
go worker(&wgWorkers, ch1, ch2, 101, 200) // Worker 2
// Create readers waitgroup with a counter of 2
wgReader := sync.WaitGroup{}
wgReader.Add(2)
// Run readers
go reader(&wgReader, ch1, 1) // Reader 1
go reader(&wgReader, ch2, 2) // Reader 2
// Wait for workers to finish
wgWorkers.Wait()
// Close workers channels
close(ch1) // Makes reader 1 exit after processing the last element in the channel
close(ch2) // Makes reader 2 exit after processing the last element in the channel
// Wait for both readers to finish processing before exiting the program
wgReader.Wait()
}
// Worker function definition
func worker(wg *sync.WaitGroup, ch1, ch2 chan<- int, from, to int) {
// Decrement worker waitgroup counter by one when function returns
defer wg.Done()
for i := from; i < to; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
// Reader function definition
func reader(wg *sync.WaitGroup, ch <-chan int, chNum int) {
// Decrement reader waitgroup counter by one when function returns
defer wg.Done()
// Here we iterate on the channel fed by worker 1 or worker 2.
// for-range on a channel exits when the channel is closed.
for i := range ch {
fmt.Printf("from ch%d: %d\n", chNum, i)
}
}
Explainations are in the code comments.
Close the channels when the workers are done. Break out of the receive loop after both channels are closed.
package main
import (
"fmt"
"sync"
)
func main() {
ch1, ch2 := func() (<-chan int, <-chan int) {
ch_1 := make(chan int)
ch_2 := make(chan int)
var wg sync.WaitGroup
wg.Add(2)
go worker_1(&wg, ch_1, ch_2)
go worker_2(&wg, ch_1, ch_2)
// Close channels after goroutiens complete.
go func() {
wg.Wait()
close(ch_1)
close(ch_2)
}()
return ch_1, ch_2
}()
// While we still have open channels ...
for ch1 != nil || ch2 != nil {
select {
case a, ok := <-ch1:
if ok {
fmt.Println("from ch1", a)
} else {
// note that channel is closed.
ch1 = nil
}
case a, ok := <-ch2:
if ok {
fmt.Println("from ch2", a)
} else {
// note that channel is closed.
ch2 = nil
}
}
}
}
func worker_1(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 0; i < 100; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
func worker_2(wg *sync.WaitGroup, ch1, ch2 chan int) {
defer wg.Done()
for i := 101; i < 200; i++ {
if i%2 == 0 {
ch1 <- i
} else {
ch2 <- i
}
}
}
Deadlock in channels communication between two packages - Golang.
I have two packages that are communicated by two channels. One is main and the other has a function. When I run it, I obtain a deadlock.
package main
import (
functionspackage "GoEjemplos/subFolder"
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
ChannelSendData := make(chan functionspackage.FunctionStruct, 1)
defer close(ChannelSendData)
data := functionspackage.FunctionStruct{
FieldOne: 3.56,
FieldTwo: 23,
}
ChannelSendData <- data
wg.Add(1)
go functionspackage.FunctionExt(ChannelSendData, &wg)
recibe := <-functionspackage.ChannelOutFunct
fmt.Println("channelOut: ", recibe)
close(functionspackage.ChannelOutFunct)
wg.Wait()
}
The other package is
package functionspackage
import "sync"
type FunctionStruct struct {
FieldOne float64
FieldTwo int
}
var ChannelOutFunct chan float64
func FunctionExt(RecibeChan chan FunctionStruct, wg *sync.WaitGroup) (ChannelOutFunct chan float64) {
reciveData := <-RecibeChan
result := reciveData.FieldOne * float64(reciveData.FieldTwo)
ChannelOutFunct <- result
wg.Done()
return ChannelOutFunct
}
This is the deadlock.
PS C:\Go-Project\src\GoEjemplos> go run main.go
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive (nil chan)]:
main.main()
C:/Go-Project/src/GoEjemplos/main.go:32 +0x13d
goroutine 19 [chan send (nil chan)]:
GoEjemplos/subFolder.FunctionExt(0xc0000d4000, 0xc0000a2070, 0xc0000c9f18)
C:/Go-Project/src/GoEjemplos/subFolder/functionsPackage.go:19 +0x85
created by main.main
C:/Go-Project/src/GoEjemplos/main.go:30 +0x11a
exit status 2
PS C:\Go-Project\src\GoEjemplos>
Could you explain it to me where is the problem?
Thanks!
The channel functionspackage.ChannelOutFunct is not initialized, thus it is a nil channel. Writing to a nil-channel or reading from a nil-channel will always block.
https://dave.cheney.net/2014/03/19/channel-axioms
I got it to work. This is the code
package main
import (
packagefunctions "GoEjemplos/subFolder"
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var ChannelSendData = make(chan packagefunctions.FunctionStruct, 0)
defer close(ChannelSendData)
var ChanReturn = make(chan float64)
defer close(ChanReturn)
data := packagefunctions.FunctionStruct{
FieldOne: 3.56,
FieldTwo: 2,
}
wg.Add(1)
go func() { ChannelSendData <- data }()
wg.Add(1)
go func() {
ChanReturn = packagefunctions.FunctionExt(ChannelSendData, &wg)
recibeChanReturn := <-ChanReturn
fmt.Println("channelOut: ", recibeChanReturn)
wg.Done()
}()
wg.Wait()
}
the other package is
package packagefunctions
import (
"fmt"
"sync"
)
type FunctionStruct struct {
FieldOne float64
FieldTwo int
}
func FunctionExt(ChanIn chan FunctionStruct, wg *sync.WaitGroup) chan float64 {
reciveData, ok := <-ChanIn
if ok == false {
fmt.Println("channel closed")
}
var result float64
result = reciveData.FieldOne * float64(reciveData.FieldTwo)
var ChannelReturn = make(chan float64, 1)
defer close(ChannelReturn)
ChannelReturn <- result
wg.Done()
return ChannelReturn
}
I need to start a number of workers with single task queue and single result queue. Each worker should be started in different goroutine. And I need to wait till all workers will be finished and task queue will be empty before exiting from program.
I have prepare small example for goroutine synchronization.
The main idea was that we count tasks in queue and waiting for all workers to finish jobs. But current implementation sometime miss values.
Why this happends and how to solve the problem?
The sample code:
import (
"fmt"
"os"
"os/signal"
"strconv"
)
const num_workers = 5
type workerChannel chan uint64
// Make channel for tasks
var workCh workerChannel
// Make channel for task counter
var cntChannel chan int
// Task counter
var tskCnt int64
// Worker function
func InitWorker(input workerChannel, result chan string, num int) {
for {
select {
case inp := <-input:
getTask()
result <- ("Worker " + strconv.Itoa(num) + ":" + strconv.FormatUint(inp, 10))
}
}
}
// Function to manage task counter
// should be in uniq goroutine
func taskCounter(inp chan int) {
for {
val := <-inp
tskCnt += int64(val)
}
}
// Put pask to the queue
func putTask(val uint64) {
func() {
fmt.Println("Put ", val)
cntChannel <- int(1)
workCh <- val
}()
}
// Get task from queue
func getTask() {
func() {
cntChannel <- int(-1)
}()
}
func main() {
// Init service channels
abort := make(chan os.Signal)
done := make(chan bool)
// init queue for results
result := make(chan string)
// init task queue
workCh = make(workerChannel)
// start some workers
for i := uint(0); i < num_workers; i++ {
go InitWorker(workCh, result, int(i))
}
// init counter for synchro
cntChannel = make(chan int)
go taskCounter(cntChannel)
// goroutine that put some tasks into queue
go func() {
for i := uint(0); i < 21; i++ {
putTask(uint64(i))
}
// wait for processing all tasks and close application
for len(cntChannel) != 0 {}
for tskCnt != 0 {}
for len(workCh) != 0 {}
for len(result) != 0 {}
// send signal for close
done <- true
}()
signal.Notify(abort, os.Interrupt)
for {
select {
case <-abort:
fmt.Println("Aborted.")
os.Exit(0)
// print results
case res := <-result:
fmt.Println(res)
case <-done:
fmt.Println("Done")
os.Exit(0)
}
}
}
Use sync.WaitGroup to wait for goroutines to complete. Close channels to cause loops reading on channels to exit.
package main
import (
"fmt"
"sync"
)
type workerChannel chan uint64
const num_workers = 5
func main() {
results := make(chan string)
workCh := make(workerChannel)
// Start workers
var wg sync.WaitGroup
wg.Add(num_workers)
for i := 0; i < num_workers; i++ {
go func(num int) {
defer wg.Done()
// Loop processing work until workCh is closed
for w := range workCh {
results <- fmt.Sprintf("worker %d, task %d", num, w)
}
}(i)
}
// Close result channel when workers are done
go func() {
wg.Wait()
close(results)
}()
// Send work to be done
go func() {
for i := 0; i < 21; i++ {
workCh <- uint64(i)
}
// Closing the channel causes workers to break out of loop
close(workCh)
}()
// Process results. Loop exits when result channel is closed.
for r := range results {
fmt.Println(r)
}
}
https://play.golang.org/p/ZifpzsP6fNv
I suggest using close(chan) for this kind of tasks.
WaitGroup version.
package main
import (
"log"
"sync"
)
func worker(in chan int, wg *sync.WaitGroup) {
defer wg.Done()
for i := range in {
log.Println(i)
}
}
func main() {
in := make(chan int)
lc := 25
maxValue := 30
wg := sync.WaitGroup{}
wg.Add(lc)
for i := 0; i < lc; i++ {
go worker(in, &wg)
}
for c := 0; c <= maxValue; c++ {
in <- c
}
close(in)
wg.Wait()
}
Channel version
package main
import (
"log"
"os"
)
func worker(in chan int, end chan struct{}) {
defer func() { end <- struct{}{} }()
for i := range in {
log.Println(i)
}
}
func main() {
in := make(chan int)
lc := 25
maxValue := 30
end := make(chan struct{})
var fin int
go func() {
for {
<-end
fin++
log.Println(`fin`, fin)
if fin == lc {
break
}
}
close(end)
os.Exit(0)
}()
for i := 0; i < lc; i++ {
go worker(in, end)
}
for c := 0; c <= maxValue; c++ {
in <- c
}
close(in)
<-make(chan struct{})
}
I started learning go recently and I am stuck on a problem.
I have a simple go routine which either returns or pushes value to a channel.
And my main fn delegates work to this routine till it meets condition or data is exhausted.
This code seem to deadlock on "found" channel. What am I doing wrong?
There are multiple workers
Item can be found in more than one worker at the same time
Once item is found, all workers should be stopped.
.
func workerRoutine(data Data, found chan bool, wg *sync.WaitGroup){
defer (*wg).Done()
// data processing
// return on false
// multiple routines can set this at the same time
found <-true
}
func main {
// ....
found:=make(chan bool)
var wg sync.WaitGroup
itemFound:=false
Loop:
for i:=0; i<limit; i++ {
select {
case <-found:
itemFound = true
break Loop
default:
if(some_check) {
wg.Add(1)
go workerRoutine(mdata,found,&wg)
}
}
}
wg.Wait()
// use itemFound
}
One possible solution is to avoid select statement and use separate goroutine for receiver (or sender, or both).
Example:
package main
import "sync"
func worker(res chan bool, wg *sync.WaitGroup) {
res <- true
wg.Done()
}
func receiver(res chan bool, wg *sync.WaitGroup) {
for range res {
}
wg.Done()
}
func main() {
var wg, wg2 sync.WaitGroup
wg.Add(1)
wg2.Add(10)
found := make(chan bool)
go receiver(found, &wg)
for i := 0; i < 10; i++ {
go worker(found, &wg2)
}
wg2.Wait()
close(found)
wg.Done()
}