下面这段代码为什么会出现死锁呢?

schrodingercatss · 2021-01-12 13:21:59 · 1042 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2021-01-12 13:21:59 的主题,其中的信息可能已经有所发展或是发生改变。

package main

import "fmt"
import "sync"

type Node struct {
    h, w int
}

var (
    arr   = make([]Node, 1e5)
    n, k  int
    ch    = make(chan int)
    judge = make(chan bool)
    wg    sync.WaitGroup
)

func check() {
    tot, num := 0, <-ch
    for i := 0; i < n; i++ {
        tot += (arr[i].h / num) * (arr[i].w / num)
        if tot >= k {
            judge <- true
            return
        }
    }
    judge <- false
}

func main() {
    fmt.Scanf("%d %d", &n, &k)
    for i := 0; i < n; i++ {
        fmt.Scanf("%d %d", &arr[i].h, &arr[i].w)
    }

    wg.Add(1)
    go check()
    go func() {
        l, r := 1, 100000
        for l < r {
            mid := (l + r + 1) >> 1
            ch <- mid
            if <-judge {
                l = mid
            } else {
                r = mid - 1
            }
        }
        ch <- l
        wg.Done()
    }()
    fmt.Println(<-ch)
    wg.Wait()
}

输入:

2 10
5 6
6 5

输出:

2

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1042 次点击  ∙  1 赞  
加入收藏 微博
2 回复  |  直到 2021-03-02 09:43:37
__Golang__
__Golang__ · #1 · 4年之前

首先输入有问题 简单看下死锁问题,ch写入mid,有可能直接被main中的fmt.Println(<-ch)读取,那么check函数锁死,if <-judge 锁死。 再看,if <-judge在for内,那么可能会读很多次,你check只执行一次即judge只写入一次。 另外,这个好像没有必要用通道吧,按顺序逻辑写就行

package main

import "fmt"
import "sync"

type Node struct {
    h, w int
}

var (
    arr   = make([]Node, 1e5)
    n, k  int
    ch    = make(chan int)
    judge = make(chan bool)
    wg    sync.WaitGroup
)

func check() {

    tot, num := 0, <-ch

    for i := 0; i < n; i++ {
        tot += (arr[i].h / num) * (arr[i].w / num)
        if tot >= k {
            judge <- true
            return
        }
    }
    judge <- false
}

func main() {
    fmt.Scanf("%d %d\n", &n, &k)

    for i := 0; i < n; i++ {
        fmt.Scanf("%d %d\n", &arr[i].h, &arr[i].w)
    }

    wg.Add(1)

    go func() {
        l, r := 1, 100000
        for l < r {
            go check()
            mid := (l + r + 1) >> 1
            ch <- mid
            if <-judge {
                l = mid
            } else {
                r = mid - 1
            }
        }
        go func(){
            ch <- l
        }()
        wg.Done()
    }()

    wg.Wait()
    fmt.Println(<-ch)

}
tanwen321
tanwen321 · #2 · 4年之前

应该是和judge通道没关系,是ch通道和wg的问题,主进程你用wg等待子进程执行完成,子进程又在等待主进程的ch读取,所以死锁了 去掉wg就行,改成这样试试

func main() {
    fmt.Scanf("%d %d", &n, &k)
    for i := 0; i < n; i++ {
        fmt.Scanf("%d %d", &arr[i].h, &arr[i].w)
    }

    // wg.Add(1)
    go check()
    go func() {
        l, r := 1, 100000
        for l < r {
            mid := (l + r + 1) >> 1
            ch <- mid
            if <-judge {
                l = mid
            } else {
                r = mid - 1
            }
        }
        ch <- l
        // wg.Done()
    }()
    fmt.Println(<-ch)
    // wg.Wait()
}
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传