S
S
Sergey Ilyin2021-09-18 12:05:53
go
Sergey Ilyin, 2021-09-18 12:05:53

Deadlock - how to close the channel correctly?

Hello! I am new to Go. The task is this: data is passed to the input, hashed and passed further to the MultiHash function, then MultiHash must read them again, hash them and pass them to the next function. An attempt to implement pipeline. An anonymous function in the main function tries to read the data and it succeeds, but after reading all the data, the program still falls into a deadlock. This article says that the program falls into a deadlock if we try to read data through range, if the channel is not closed. Am I right in thinking that I have the same error? I tried everything and an infinite loop and select and close the channel, if I close it in MultiHash, I have a panic. Could you explain what is my mistake and how to fix it?

signer.go

package main

import (
  "fmt"
  "os"
  "strconv"
  "sync"
)

// сюда писать код

func SingleHash(wg *sync.WaitGroup, done chan interface{}, in []string) {
  defer close(done)
  defer wg.Done()

  fmt.Println(in)
  wgsh := &sync.WaitGroup{}
  mu := &sync.Mutex{}

  for _, i := range in {
    wgsh.Add(1)
    go workerSingleHash(wgsh, mu, i, done)
  }

  wgsh.Wait()
  fmt.Println("end singlehash")

}

func workerSingleHash(wg *sync.WaitGroup, mu *sync.Mutex, in string, done chan interface{}) {

  defer wg.Done()

  crc32Chan := make(chan string)

  mu.Lock()
  md5Data := DataSignerMd5(in)
  mu.Unlock()

  go asyncCrc32Signer(in, crc32Chan)

  crc32Data := <-crc32Chan
  crc32Md5Data := DataSignerCrc32(md5Data)

  done <- crc32Data + "~" + crc32Md5Data
}

func asyncCrc32Signer(data string, out chan string) {
  //defer close(out)
  out <- DataSignerCrc32(data)
}

func MultiHash(wg *sync.WaitGroup, done chan interface{}, done2 chan string) chan string {
  wgD := &sync.WaitGroup{}

  defer wg.Done()
  j := 0
  for v := range done {
    fmt.Println("v: ", v)
    str := fmt.Sprintf("%v", v)
    wgD.Add(1)
    go asyncWorker(wgD, j, str, done2)
    j++
  }

  wgD.Wait()

  return done2
}

func asyncWorker(wgDone2 *sync.WaitGroup, increment int, in string, done2 chan string) {
  wgDone2.Done()
  j := strconv.Itoa(increment)
  done2 <- DataSignerCrc32(j + in)
}


func main() {

  wg := &sync.WaitGroup{}
  wg.Add(2)
  done := make(chan interface{})
  done2 := make(chan string)
  in := os.Args

  go SingleHash(wg, done, in[1:])

  result := MultiHash(wg, done, done2)

  func(done2 chan string) {
    for v := range done2 {
      fmt.Println("combine result: ", v)
    }
  }(result)

  wg.Wait()
  fmt.Println("end")
}


These are functions that hash, DataSignerCrc32 cannot be used immediately one by one, as overheating occurs, they need to be parallelized. this file is not mine - this is a condition and I dealt with it, but this is not the problem, I just post it so that they can understand what these
common.go functions are
package main

import (
  "crypto/md5"
  "fmt"
  "hash/crc32"
  "strconv"
  "sync/atomic"
  "time"
)

type job func(in, out chan interface{})

const (
  MaxInputDataLen = 100
)

var (
  dataSignerOverheat uint32 = 0
  DataSignerSalt            = ""
)

var OverheatLock = func() {
  for {
    if swapped := atomic.CompareAndSwapUint32(&dataSignerOverheat, 0, 1); !swapped {
      fmt.Println("OverheatLock happend")
      time.Sleep(time.Second)
    } else {
      break
    }
  }
}

var OverheatUnlock = func() {
  for {
    if swapped := atomic.CompareAndSwapUint32(&dataSignerOverheat, 1, 0); !swapped {
      fmt.Println("OverheatUnlock happend")
      time.Sleep(time.Second)
    } else {
      break
    }
  }
}

var DataSignerMd5 = func(data string) string {
  OverheatLock()
  defer OverheatUnlock()
  data += DataSignerSalt
  dataHash := fmt.Sprintf("%x", md5.Sum([]byte(data)))
  time.Sleep(10 * time.Millisecond)
  return dataHash
}

var DataSignerCrc32 = func(data string) string {
  data += DataSignerSalt
  crcH := crc32.ChecksumIEEE([]byte(data))
  dataHash := strconv.FormatUint(uint64(crcH), 10)
  time.Sleep(time.Second)
  return dataHash
}


OUT:
[3 4 5 6]
v:  4088798008~2157876746
v:  498629140~3068393833
v:  2226203566~3690458478
v:  1842515611~1684880638
end singlehash
combine result:  1341606222
combine result:  4202847257
combine result:  966776312
combine result:  1549563179
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main.func1(0xc000086120)
        C:/Users/engis/OneDrive/Рабочий стол/Go-learn-master/Go-learn-master/hw2_signer/signer.go:91 +0xe5
main.main()
        C:/Users/engis/OneDrive/Рабочий стол/Go-learn-master/Go-learn-master/hw2_signer/signer.go:94 +0x13b
exit status 2

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
igorzakhar, 2021-09-20
@igorzakhar

My version: https://github.com/igorzakhar/pipeline_signer/blob...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question