Photo taken on October 3, 2021, My Faith.

It’s time to get up after lying down too long.

I’d rather roll someone else than let them roll me.

I have read the source code of several modules of Go intermittently before, but I have never written, resulting in some details that I can’t remember. To write a series of articles to re-record.

Channel source code parsing too many articles. Most people have no patience to read a long article, so I plan to write it separately and attach a complete PPT at the end.

Of course, this will not involve too much detail source code, because sometimes, the details are the devil.

introduce

It’s 1202, and I don’t believe anyone who’s used Go hasn’t used Channel.

Of course, the picture below also covers most of the gestures.

There is a classic problem that uses channel for task scheduling. The title is as follows:

There are four Goroutines, numbered 1, 2, 3 and 4. Every second a Goroutine prints its own number. Implement this program so that the output numbers are always 1, 2, 3, 4, 1, 2, 3, 4… Print out the sequence of. Like this,

You can think about it first, the code can also be obtained through the background reply drum pass.

The principle of analytic

Let’s start with a simple example.

Create a main.go file with the following code:

Let’s see what this code looks like when compiled.

It’s not hard to come up with assembly code for the Go program.

Use the go tool compile -n -l -s main.go to generate assembly code:

Or run the go tool compile -n -l main.go command to compile the code and then run the go tool objdump main.o command to disassemble the code.

You can also get the compiled code by going build-gcflags -s main.go.

I’m not going to show you the above two, but you can experiment. The specific meaning of flag among them can also be understood by oneself.

If you find it a bit cumbersome to type your own code above, I recommend a more direct visualization tool.

To sum up, we can see from the compiled code that the above initialization of a channel,

ch := make(chan struct{})
Copy the code

It actually calls Runtime.makechan.

And we know from the function that we’re going to return oneruntime.hchanThe pointer.

The runtime hchan structure.

We will first explain the meanings of the various fields of the Hchan structure, and then explain their functions in more detail in the case description.

What’s the difference between qcount and dataqsiz?

You go to the bank, and the bank has 5 Windows, so dataqsiz is equal to 5. In this case, channel capacity is 5. When you go to the bank, there are three Windows where someone is currently doing something, so qcount equals 3, indicating that channel currently has three data elements. Then the bank can receive two more customers and send two data elements to the channel.

For the other fields, just look at the instructions for now, and we’ll talk more about them later.

Creating a channel is essentially a runtime.hchan pointer, and any subsequent operations on this chan are simply operations on the structure field.

We can also guess why a channel can pass messages in different G’s without worrying about concurrency for the consumer.

Hchan uses mutex internally to ensure concurrency security.

Finally, let’s take a look at the runtime.makechan core implementation.

You can see that there is a switch branch at the time of creation, so when will the corresponding case be used?

Based on the above information, we can conclude that

  • If you create an unbuffered channel, you only need to allocate a chunk of memory for runtime.hchan itself.

  • If the created buffer channel stores a type other than a pointer, a contiguous chunk of memory is allocated for the current channel and the buffer that stores elements of the type.

  • By default (the buffer channel storage type contains Pointers), memory is allocated for runtime.hchan and buffer separately.

conclusion

This article mainly introduces how to obtain the assembly code of go program, through the assembly code to know the specific function that creates channel runtime.makechan.

We also know that different creation postures lead to different memory allocation logic.

Finally, by creating a function, we know that a channel is represented by runtime.hchan when the program runs.

Understand the Principle of Channel once and for all

This article uses the article synchronization assistant to synchronize