Table of Contents
Question content
Workaround
Home Backend Development Golang Go program works with single channel and gets into deadlock when new channel is introduced

Go program works with single channel and gets into deadlock when new channel is introduced

Feb 09, 2024 pm 11:20 PM
go language overflow

Go 程序使用单通道工作,并在引入新通道时陷入死锁

In the Go language, concurrent operations of the program are implemented through channels. A channel is a special type used to transfer data. It allows data exchange and communication between goroutines. However, if you work with a single channel in your program and do not handle it correctly when introducing a new channel, deadlock may occur. In this article, PHP editor Xiaoxin will explain in detail the single-channel work and deadlock issues in Go programs, and how to avoid deadlocks.

Question content

I am new to Go channels and I am trying to learn Go channels by building a mock kernel and handling interactions through channels. The goal of this sample program is to have multiple processes (2) simultaneously send memory allocation requests to the kernel using single channel , and other processes to send release memory requests using Single but distinct channels to the kernel.

+-------------+
                           +------------------+       |             |
                          -> Alloc. Mem. Ch.  |<--\   |             |
+-----------------+   ---/ +------------------+   >-->|   Kernel    |
|   Process A     |<--     +------------------+ -/    |             |
+-----------------+   \--> |  Realse Mem. Ch. |<      |             |
                           +------------------+       +-------------+
Copy after login

If I only have allocation requests, the program works, once I introduce release requests, the program gets into a deadlock.

Please note that the process also creates a reply queue when sending an allocation request, however, this is not shown in the above image because it is not part of the problem.

The complete procedure is as follows:

package main

import (
        "fmt"
        // "log"
        "time"
)

const (
        _ float64 = iota
        LowPrio
        MedPrio
        HghPrio
)

// Kernel type to communicate between processes and memory resources
type Kernel struct {
        reqMemCh chan chan int
        rlsMemCh chan int
}

func (k *Kernel) Init() {
        k.reqMemCh = make(chan chan int, 2)
        k.rlsMemCh = make(chan int, 2)
        go k.AllocMem()
        go k.RlsMem()
}

// Fetch memory on process request
func (k *Kernel) GetReqMemCh() chan chan int {
        return k.reqMemCh
}

func (k *Kernel) GetRlsMemCh() chan int {
        return k.rlsMemCh
}

func (k *Kernel) AllocMem() {
        // loop over the items (process reply channels) received over
        // the request channel
        for pCh := range k.GetReqMemCh() {
                // for now think 0 is the available index
                // send this as a reply to the exclusive process reply channel
                pCh <- 0
                close(pCh)
        }
}

// Release memory
func (k *Kernel) RlsMem() {
        // we do not have to anything here
}

// Process type which requests memory
type Proc struct {
        ind     int
        prio    float64
        exeT    time.Time
        count   int
        memInd  int
        rqMemCh chan chan int
        rlMemCh chan int
}

func (p *Proc) Init(
        ind int,
        prio float64,
        rqMemCh chan chan int,
        rlMemCh chan int,
) {
        p.ind = ind
        p.prio = prio
        p.memInd = -1
        p.rqMemCh = rqMemCh
        p.rlMemCh = rlMemCh
}

func (p *Proc) GetReqMemCh() chan chan int {
        return p.rqMemCh
}

func (p *Proc) GetRlsMemCh() chan int {
        return p.rlMemCh
}

func (p *Proc) ReqMem() {
        // create the reply channel exclusive to the process
        // this channel will return the allocated memeory id/address
        rpCh := make(chan int)
        // send the reply channel through the request channel
        // to get back the allocation memory id
        p.GetReqMemCh() <- rpCh
        // Below line is blocking ...
        for mi := range rpCh {
                p.memInd = mi
        }
}

func (p Proc) RlsMem() {
        p.GetRlsMemCh() <- 0
}

func (p Proc) String() string {
        return fmt.Sprintf(
                "Proc(%d): Memory(%d), Count(%d)",
                p.ind+1, p.memInd+1, p.count,
        )
}

func main() {

        k := &Kernel{}
        k.Init()

        p := &Proc{}
        for i := 0; i < 3; i++ {
                p.Init(i, LowPrio, k.GetReqMemCh(), k.GetRlsMemCh())
                p.ReqMem()
                p.RlsMem()
        }

        time.Sleep(time.Second)
}
Copy after login

Exceptions are as follows:

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.Proc.RlsMem(...)
        main.go:100
main.main()
        main.go:119 +0xc5

goroutine 6 [chan receive]:
main.(*Kernel).AllocMem(0x0?)
        main.go:41 +0x5e
created by main.(*Kernel).Init in goroutine 1
        main.go:25 +0xc5
exit status 2
Copy after login

Any help would be greatly appreciated.

cheers,

DD.

Workaround

As British commenter, you have a buffer channel that has reached its capacity but has nothing to read.

According to the language tour (1 2), blocks are sent and received until the other party is ready. Although buffered channels provide some tolerance here, once the buffer is full, the behavior is the same.

This problem can be solved by adding a user of k.rlsMemCh. If you don't have anything planned for this, delete the channel or use logic to drain it temporarily.

<code>func (k *Kernel) Init() {
        k.reqMemCh = make(chan chan int, 2)
        k.rlsMemCh = make(chan int, 2)
        go k.AllocMem()
        go k.RlsMem()
}

func (k *Kernel) AllocMem() {
        for pCh := range k.GetReqMemCh() {
                pCh <- 0
                close(pCh)
        }
}

func (k *Kernel) RlsMem() {
        // TODO: Add a for-select or for-range over k.rlsMemCh here
}

</code>
Copy after login

Drainage may look like this:

func (k *Kernel) RlsMem() {
        for {
                <-k.GetRlsMemCh()
        }
}
Copy after login

The above is the detailed content of Go program works with single channel and gets into deadlock when new channel is introduced. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
1 months ago By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
1 months ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What is the problem with Queue thread in Go's crawler Colly? What is the problem with Queue thread in Go's crawler Colly? Apr 02, 2025 pm 02:09 PM

Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

What libraries are used for floating point number operations in Go? What libraries are used for floating point number operations in Go? Apr 02, 2025 pm 02:06 PM

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

How to solve the problem that custom structure labels in Goland do not take effect? How to solve the problem that custom structure labels in Goland do not take effect? Apr 02, 2025 pm 12:51 PM

Regarding the problem of custom structure tags in Goland When using Goland for Go language development, you often encounter some configuration problems. One of them is...

Which libraries in Go are developed by large companies or provided by well-known open source projects? Which libraries in Go are developed by large companies or provided by well-known open source projects? Apr 02, 2025 pm 04:12 PM

Which libraries in Go are developed by large companies or well-known open source projects? When programming in Go, developers often encounter some common needs, ...

In Go, why does printing strings with Println and string() functions have different effects? In Go, why does printing strings with Println and string() functions have different effects? Apr 02, 2025 pm 02:03 PM

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

Bytes.Buffer in Go language causes memory leak: How does the client correctly close the response body to avoid memory usage? Bytes.Buffer in Go language causes memory leak: How does the client correctly close the response body to avoid memory usage? Apr 02, 2025 pm 02:27 PM

Analysis of memory leaks caused by bytes.makeSlice in Go language In Go language development, if the bytes.Buffer is used to splice strings, if the processing is not done properly...

Why is it necessary to pass pointers when using Go and viper libraries? Why is it necessary to pass pointers when using Go and viper libraries? Apr 02, 2025 pm 04:00 PM

Go pointer syntax and addressing problems in the use of viper library When programming in Go language, it is crucial to understand the syntax and usage of pointers, especially in...

Go language is inefficient in processing massive URL access, how to optimize it? Go language is inefficient in processing massive URL access, how to optimize it? Apr 02, 2025 am 10:15 AM

Performance optimization strategy for Go language massive URL access This article proposes a performance optimization solution for the problem of using Go language to process massive URL access. Existing programs from CSV...

See all articles