我知道sync
包和它的waitgroup
选项,我不想在这个测试中使用它,我正在测试一种信号量。
所以我有:
package main
import (
"fmt"
"os"
"time"
)
func main() {
fmt.Print("wassap")
jobs := make(chan int)
processStarted := make(chan struct{}, 1)
processCompleted := make(chan struct{}, 1)
createJobs(jobs)
go func() {
worker(jobs, processStarted, processCompleted)
}()
go func() {
sync(processStarted, processCompleted)
}()
time.Sleep(3600 * time.Second)
fmt.Print("\nend of main...")
interrupt := make(chan os.Signal)
<-interrupt
}
func createJobs(jobs chan<- int) {
defer close(jobs)
for i := 1; i < 20; i++ {
jobs <- i
}
}
func worker(jobs <-chan int, processStarted <-chan struct{}, processCompleted <-chan struct{}) {
for {
select {
case i := <-jobs:
fmt.Printf("\nFetching job #%d from channel", i)
time.Sleep(2 * time.Second)
case <-processStarted:
fmt.Print("\nProcess Started. Waiting for it to be completed")
<-processCompleted
fmt.Print("\nProcess completed")
}
}
}
func sync(processStarted chan<- struct{}, processCompleted chan<- struct{}) {
// acquire semaphore. Send signal to channel to indicate that it is busy
processStarted <- struct{}{}
for i := 1; i < 5; i++ {
fmt.Printf("\nprocessing %d", i)
time.Sleep(5 * time.Second)
}
// release semaphore
processCompleted <- struct{}{}
}
我想测试的其实很简单我有一个createJobs
函数,它的唯一目的是向一个通道添加元素,在本例中是一个int通道。然后我有一个worker
,它将从该通道中取出对象,并在取出下一个元素之前休眠2秒。
现在,还有一个同步函数。这个函数的唯一目的是模拟在worker
运行时启动的进程。如果这个进程是活动的,那么在sync
结束时,jobs
元素的处理应该停止,这就是为什么我有两个通道,一个指示进程开始,另一个指示进程结束。
当运行我的代码时,我得到以下错误:
致命错误:所有的goroutine都处于休眠状态-死锁!
如果我修改createJobs
的调用方式,将其 Package 在一个goroutine中,如下所示:
go func() {
createJobs(jobs)
}()
那么我的代码就能正常运行。
我只想知道为什么会这样。我是说:main
例程正在执行,然后它会调用createJobs
(无回绕),所以main
例程应该被阻塞,直到这个调用结束。一旦createJobs
结束,这意味着通道中有元素。main
继续执行,并启动其他goroutine worker
和sync
来完成它们的工作。在main
结束之前,我只是简单地添加了一个sleeper,以便为之前创建的goroutine给予时间来完成。
我不是在问这个问题的其他解决方案,我只是想知道当createJobs
发生在goroutine之外时会发生什么。
2条答案
按热度按时间xfb7svmp1#
你将
jobs
声明为一个无缓冲的通道,然后试图同步地将20个值推入其中。这将在你调用createJobs(jobs)
时阻塞你的main函数。将第13行改为:
……将打破僵局。
rfbsl7qr2#
以前的解决方案完全有效。但您也可以使用
如果您仍然想保持默认通道大小。