duanlie3187 2019-02-12 14:26
浏览 48

避免goroutine之间的双向通信中的死锁

I am making my first experiences in Go, and so far I really like the goroutine and channels construct. I am wondering if there is an idiomatic way to avoid deadlocks in bidirectional communication between multiple goroutines. Consider the following example. There are three goroutines: producer, worker and controller.

  • The producer produces integers. In reality this could be data coming from a network connection for example.

  • The worker receives data from the producer and does some operation on it. Then, the worker directs the modified data to the controller.

  • The controller sends a command to the worker in some cases. In the example this would happen if the received integer is bigger than 180.

The deadlock happens when the controller tries to send a command to the worker, while the worker tries to send an integer to the controller.

producerToWorker := make(chan int)
workerToController := make(chan int)
controllerToWorker := make(chan bool) // bool represents a command for this example

// Worker
go func() {
    for {
        select {
        case i := <-producerToWorker:
            // Do some processing and send to controller
            workerToController <- (2 * i) + 1
        case <-controllerToWorker:
            // Would react to the command here
        }
    }
}()

// Controller
go func() {
    for {
        select {
        case i := <-workerToController:
            fmt.Println(i)
            if i > 180 {
                // Send a command to the worker
                controllerToWorker <- true
            }
        }
    }
}()

// Producer
for {
    producerToWorker <- rand.Intn(100)
}

Example output:

163
175
95
113
1
189 // No deadlock
23
125
179
57
149
23
91
191 // No deadlock
133
95
175
177
181 // No deadlock
17
175
63
27
181 // Deadlock!
fatal error: all goroutines are asleep - deadlock!

Buffering the channels would make this deadlock more unlikely, but not solve it logically. I would like to avoid mutexes if possible. How do you handle such situations in Go?

Edit: To give a more real-world description: I came across this problem when I tried to implement a websocket client. The websocket client (worker) connects to an external service (producer) and receives messages from it (producerToWorker) and passes them to the controller (workerToController) to handle the received messages. The controller needs to react to the received messages, for example send a response or disconnect the client when an invalid message is received (controllerToWorker).

  • 写回答

1条回答 默认 最新

  • duanpuchen3142 2019-02-12 14:32
    关注

    [Is there ]an idiomatic way to avoid deadlocks in bidirectional communication between multiple goroutines?

    No. Nothing "idiomatic" or based on a "pattern".

    How do you handle such situations in Go?

    You redesign. Concurrent circular data flow is best avoided.

    评论

报告相同问题?

悬赏问题

  • ¥100 set_link_state
  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度