In-depth exploration of the C++ object model.pdf

Content Introduction
"Deep Exploration of C++ Object Model" Focus: Explore program behavior under "C++ Object Model Supported by Object-Oriented Programs". Provide a clear understanding of "the basic realization technology of object-oriented nature" and "the implicit interest exchange behind various properties". Check the efficiency impact caused by program deformation. Provide a wealth of program examples, pictures, and efficiency measurements between object-oriented concepts and the underlying object model. Inside The C++ Object Model focuses on the underlying mechanism of C++ object-oriented programming, including structural semantics, temporary object generation, encapsulation, inheritance, and virtual-virtual functions and virtual inheritance. This "Deep Exploration of C++ Object Model" lets you know: once you can understand the underlying implementation model, how much efficiency your program code will gain. Lippman clarified those extra negatives about C++

File: n459.com/file/25127180-479205949

The following are irrelevant:

-------------------------------------------Dividing line----- ----------------------------------------

It’s been a long time since I wrote a blog. I have to say that Go Language Lovers Weekly is a treasure. I wanted to take a look at it to pass the time. I didn’t expect it to give me a long-lost inspiration.

There is a very interesting topic in the 78th issue of Go Language Lovers Weekly.

Let's look at the topic. First give the following code:

package main

import (
“fmt”
“time”
)

func main() { ch1 := make(chan int) go fmt.Println(<-ch1) ch1 <- 5 time.Sleep(1 * time.Second) } What is the output of this code?





The first thing I thought of was 5. After all, the code is very simple. If the response is quicker, the result will be inferred after reading the code.

However, one of the options given in the title is output deadlock error. This option aroused my curiosity, so I ran it:

$ go run a.go

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()
/tmp/a.go:10 +0x65
exit status 2
Ah here. It's really deadlocked. So I guess it is related to the order of execution? So I wrote a script to run 1000 times to see:

#!/bin/bash

for i in {0…1000}
do
go run a.go &> /dev/null
if [$? -eq 0]
then echo'success
!'
break
fi
done The
result is naturally unsuccessful once, even if you change it to 10000 Even 1,000,000 is the same. We can eliminate the impact of execution order.

If you observe carefully, all errors are the same: goroutine 1 [chan receive]:, deadlock here.

Could it be due to the use of unbuffered chan? Golang's memory model stipulates that unbuffered chan accepts happens before sending operations. Will this have an impact (in fact, if you think about it, it will be quickly ruled out. What happens before determines the visibility of the memory, not the execution of instructions. Time sequence), so I changed the code:

func main() { ch1 := make(chan int, 100) go fmt.Println(<-ch1) ch1 <- 5 time.Sleep(1 * time.Second) } This time we used a one that holds 100 elements The buff channel, but the result has not changed a little.





My thoughts are interrupted here.

But I still have google, so I searched for a keyword with "golang channel deadlock" and found some interesting results.

That is, all chan's deadlock code can basically be abstracted into the following form:

func main() { ch1 := make(chan int) // Whether there is a buff has no effect_ = <-chan ch1 <- 5 } This code will undoubtedly deadlock, because it receives a value from chan and chan is Empty will cause the current goroutine to enter the wait, and if the current goroutine cannot continue to run, there will never be a way to write a value to chan, and the deadlock occurs here.




Upon closer inspection, you will find that the code of the title is very similar to this:

func main() { ch1 := make(chan int) go fmt.Println(<-ch1) ch1 <- 5 // sleep is to prevent the main routine from exiting prematurely } There is only one answer, <-ch1 occurs in the main goroutine Inside.





In order to support this point of view, I have consulted the golang language spec. The description of the go statement is as follows:

The function value and parameters are evaluated as usual in the calling goroutine, but unlike with a regular call, program execution does not wait for the invoked function to complete.

The function and its parameters will be executed in the goroutine that uses the go statement as usual, but unlike regular function calls, the program will not wait for the execution of the function to complete.

If you are looking at the part about evaluation:

calls f with arguments a1, a2, … an. Except for one special case, arguments must be single-valued expressions assignable to the parameter types of F and are evaluated before the function is called.

Calling function f with parameters a1, a2, etc., except for a special case, they must all be single-valued expressions and be evaluated before the function runs.

The special case mentioned above is method invocation, and the receiver of the method will be passed to the method in a specific location.

The ins and outs of this matter will be clear, let's sort it out.

Suppose we start a child goroutine called b in the main goroutine, then what actually happens in the main goroutine is this:

The main goroutine executes to the go statement. The
go statement finds that the following function expression needs to pass parameters. The
passed parameters are evaluated in the main goroutine. A
new goroutine b is created, and the just evaluated parameters are passed to the function to be executed (assuming it is called f ), f starts to execute the
go statement in goroutine b and ends, and the control flow returns to the main goroutine,
so the chan receiving operation in go fmt.Println(<-ch1) is executed in the main goroutine, so deadlock is a certainty.

If you change to the following, the deadlock will not occur:

package main

import (
“fmt”
“time”
)

func main() { ch1 := make(chan int) go func() { fmt.Println(<-ch1) }() ch1 <- 5 time.Sleep(1 * time.Second) } This is because of <-ch1 This time the real thing happened in different goroutines, and the deadlock naturally disappeared.







This question is very bad, the bad is that the form of fmt.Println(...) is confusing, thinking that the call itself is executed in the new goroutine, but what is actually executed in the new goroutine is the function inside fmt.Println Implementation code, instead of the sentence fmt.Println(...), the parameter will be evaluated before that.

So what can we learn from this? The answer is to never write code like the one in the title. For chan operations, make sure to run in a different routine from the goroutine that executes the go statement.

But everything is not absolute, there will be some exceptions to the buffed chan, of course, I have a chance to talk about it later :P

Guess you like

Origin blog.csdn.net/gumenghua_com1/article/details/112763030