@wubbacom
PHP developer

Deadlock — как правильно закрыть канал?

Всем привет! Я новичок в Go. Задача такая: во вход передаются данные, хешируются и передаются дальше в функцию MultiHash, дальше MultiHash должна их прочесть еще раз захешировать и передать следующей функции. Попытка реализовать pipeline. Анонимная функция в функции main, пытается прочесть данные и у нее это получается, но после прочтения всех данных программа все равно впадает в deadlock. В этой статье сказано, что программа впадает в deadlock если мы пытаемся прочесть данные через range, если канал не закрыт. Правильно ли считаю, что у меня такая же ошибка? Я все перепробовал и бесконечный цикл и select и закрывать канал, если закрывать в MultiHash, у меня возникает паника. Могли бы вы объяснить в чем моя ошибка и как исправить?

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")
}


Это функции которые хешируют, DataSignerCrc32 нельзя использовать сраза одну за одной, так как случается перегрев, их нужно распараллелить. этот файл не мой - это условие и я с ним справился, но проблема не в этом, просто выкладываю, что б могли понять что это за функции
common.go
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
  • Вопрос задан
  • 418 просмотров
Пригласить эксперта
Ответы на вопрос 1
igorzakhar
@igorzakhar
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы