0

0

当填充通道的函数调用未嵌入 Goroutine 中时,为什么会出现死锁?

王林

王林

发布时间:2024-02-10 12:00:10

|

797人浏览过

|

来源于stackoverflow

转载

当填充通道的函数调用未嵌入 goroutine 中时,为什么会出现死锁?

当填充通道的函数调用未嵌入Goroutine中时,会出现死锁的原因是因为通道的发送和接收操作是阻塞的。如果在主Goroutine中调用填充通道的函数,并且该函数内部没有将填充操作放入新的Goroutine中运行,那么主Goroutine会一直等待通道有足够的空间来接收数据,而填充操作又无法进行,从而导致死锁的产生。因此,为了避免死锁,我们需要在填充通道的操作中使用Goroutine来进行并发执行,以确保填充操作和接收操作可以同时进行。

问题内容

我知道 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 元素,这就是为什么我有两个通道,一个表示进程已启动,另一个表示进程结束。

运行我的代码时出现以下错误:

fatal error: all goroutines are asleep - deadlock!

如果我修改 createjobs 的调用方式,将其包装在如下所示的 goroutine 中:

go func() {
        createJobs(jobs)
    }()

然后我的代码运行正确。

我只是想了解为什么会发生这种情况。我的意思是: main 例程正在执行,然后它调用 createjobs (无换行),因此 main 例程应该被阻止,直到此调用结束。一旦 createjobs 结束,就说明通道中有元素了。 main 继续执行并启动其他 goroutine workersync 来完成它们的工作。在 main 结束之前,我只是添加一个睡眠程序,以便为之前创建的 goroutine 提供完成时间。

我不是在询问这个问题的其他解决方案,我只是想知道当 createjobs 发生在 goroutine 之外时会发生什么。

Artifact News
Artifact News

由AI驱动的个性化新闻推送

下载

解决方法

您将 jobs 声明为无缓冲通道,然后尝试将 20 个值同步推入其中。当您调用 createjobs(jobs) 时,这将阻止您的主函数。

将第 13 行更改为:

    jobs := make(chan int, 20)

...将解决僵局。

编辑 - 评论中要求的澄清:

无缓冲通道没有容量,并且会阻止生产者的执行,直到消费者收到消息为止。

无缓冲通道的一个很好的类比是管道,在本例中,过程如下所示:

+------------------+     +------------+      +-------------+
| PRODUCER         |     | PIPE       |      | CONSUMER    |
|                  +---->|            +----->|             |
| createJobs(jobs) |     | unbuffered |      | worker(...) |
|                  |     | channel    |      |             |
+------------------+     +------------+      +-------------+

发生死锁是因为 createjobs(jobs) 被同步调用,并且还没有消费者在运行。

当在 goroutine 中调用函数(producer)时它可以工作,因为基本上插入通道和读取通道是并行发生的?

是的。如果生产者被异步调用,它不会阻塞 main() 函数,因此消费者也将有机会被调用。在这种情况下,生产者将一一推送其所有任务,就像工作人员一一消费它们一样。

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

401

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

543

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

53

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

197

2025.08.29

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

63

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

60

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

238

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

400

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

17

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号