I'm currently reading the slices of Go Concurrency Patterns. I'm a little bit confused about a seeming contradiction between a statement on slide #16:
When main returns, the program exits and takes the boring function down with it.
and another one on slide #19 (in combination with the example on slide #20):
A channel in Go provides a connection between two goroutines, allowing them to communicate.
If main is just a goroutine, how can it cause any another (spawned) goroutine to stop, in other words: in what sense is the goroutine named main special?*
* I searched for it, but found nothing obviously enlightening so far; the SO question with the promising title Difference between the main goroutine and spawned goroutines of a Go program asks for a completely different issue.
edit: changed the title, to focus on the difference between main and "normal" goroutines (after stumbling upon the Go runtime function Goexit)
edit: simplified question, to be even more focused on the specifics of main
I think you need to consider the goroutine implications separately to the process implications.
The main() function is a goroutine (or if you want to be really picky, called from an implicitly created goroutine). Using go creates other goroutines. Returning from main() terminates its goroutine but also terminates the process as a whole (and thus all other goroutines). It is also possible to terminate the process as a whole by calling os.Exit() or similar from any goroutine.
Related
I know you can define functions called init in any package, and these function will be executed before main. I use this to open my log file and my DB connection.
Is there a way to define code that will be executed when the program ends, either because it reaches the end of the main function or because it was interrupted ? The only way I can think of is by manually calling a deffered terminate function on each package used by main, but that's quite verbose and error prone.
The C atexit functionality was considered by the Go developers and the idea of adopting it was rejected.
From one of the related thread at golang-nuts:
Russ Cox:
Atexit may make sense in single-threaded, short-lived
programs, but I am skeptical that it has a place in a
long-running multi-threaded server.
I've seen many C++ programs that hang on exit because
they're running global destructors that don't really need to
run, and those destructors are cleaning up and freeing
memory that would be reclaimed by the operating system
anyway, if only the program could get to the exit system call.
Compared to all that pain, needing to call Flush when you're
one with a buffer seems entirely reasonable and is
necessary anyway for correct execution of long-running
programs.
Even ignoring that problem, atexit introduces even more
threads of control, and you have to answer questions like
do all the other goroutines stop before the atexit handlers
run? If not, how do they avoid interfering? If so, what if
one holds a lock that the handler needs? And on and on.
I'm not at all inclined to add Atexit.
Ian Lance Taylor:
The only fully reliable mechanism is a wrapper program that invokes the
real program and does the cleanup when the real program completes. That
is true in any language, not just Go.
In my somewhat unformed opinion, os.AtExit is not a great idea. It is
an unstructured facility that causes stuff to happen at program exit
time in an unpredictable order. It leads to weird scenarios like
programs that take a long time just to exit, an operation that should be
very fast. It also leads to weird functions like the C function _exit,
which more or less means exit-but-don't-run-atexit-functions.
That said, I think a special exit function corresponding to the init
function is an interesting idea. It would have the structure that
os.AtExit lacks (namely, exit functions are run in reverse order of when
init functions are run).
But exit functions won't help you if your program gets killed by the
kernel, or crashes because you call some C code that gets a segmentation
violation.
In general, I agree with jnml's answer. Should you however still want to do it, you could use defer in the main() function, like this: http://play.golang.org/p/aUdFXHtFOM.
I was doing some debugging and had a bit of code like this:
go func() {
if !finished {
fmt.Println("Writing the data")
writer.Write(data)
}
}()
The finished variable is meant as a guard against writing to a writer that has been closed. However, it wasn't working. It appeared to be getting passed the flag. I determined that the call to Println was yielding the goroutine, which could allow the writer to be closed after checking the flag but before attempting the write. Sure enough, removing the call seems to have fixed it. However, I wanted to verify, and more importantly ask for suggestions on how to avoid this properly, rather than just avoiding prints in there.
Any I/O, yes, including fmt.Println, can cause a pause in goroutine execution.
But in practice, this shouldn't matter, as on any modern hardware, with more than one CPU core, you can experience a race even if the goroutine isn't paused.
You should always make your code concurrency safe.
As tile, I am referring to Go package sync.Map, can its functions be considered as atomic? Mainly the Load, Store, LoadOrStore, and Delete function.
I also build a simple example go playground, is it guaranteed that only one goroutine can enter the code range line 15 - 17? As my test seems it can be guaranteed.
Please help to explain.
The godoc page for the sync package says: "Map is like a Go map[interface{}]interface{} but is safe for concurrent use by multiple goroutines without additional locking or coordination."
This statement guarantees that there's no need for additional mutexes or synchronization across goroutines. I wouldn't call that claim "atomic" (which has a very precise meaning), but it does mean that you don't have to worry about multiple goroutines being able to enter a LoadOrStore block (with the same key) like in your example.
Is there a way in go, possibly with some debug flag switched on, to obtain a dump of the stack traces of all goroutines along with the stack traces of the "parent" goroutines (using "parent" here to mean the goroutine that executed the call to go foo() that launched the goroutine in question). The context for this question is that I have a connection leak and noticed there are many goroutines blocked on awaitDone (in the sql package), and these goroutines were spawned where the connections were created.
runtime.Stack() will give you all the stack information that the runtime is aware of.
Reading the output you can see, for Goroutines, they are designed to contain no information of its ancestors.
However, in the stack output, you do have access to where a goroutine was created. You can, technically, auto cross match that with other Goroutine's stack output to deduce the topology partially and inaccurately.
AFAIK, this is how many Golang IDEs tackle the debugging problem. Unless Golang core team changes its mind on Goroutine's metadata, I think this is the best option possible.
If I understand what you're asking, you can probably print/output the info you want using the runtime package.
Take a look at
https://golang.org/pkg/runtime/#Caller and the skip paramter. Plus the frame docs: https://golang.org/pkg/runtime/#Frames
Is that what you're after?
I know you can define functions called init in any package, and these function will be executed before main. I use this to open my log file and my DB connection.
Is there a way to define code that will be executed when the program ends, either because it reaches the end of the main function or because it was interrupted ? The only way I can think of is by manually calling a deffered terminate function on each package used by main, but that's quite verbose and error prone.
The C atexit functionality was considered by the Go developers and the idea of adopting it was rejected.
From one of the related thread at golang-nuts:
Russ Cox:
Atexit may make sense in single-threaded, short-lived
programs, but I am skeptical that it has a place in a
long-running multi-threaded server.
I've seen many C++ programs that hang on exit because
they're running global destructors that don't really need to
run, and those destructors are cleaning up and freeing
memory that would be reclaimed by the operating system
anyway, if only the program could get to the exit system call.
Compared to all that pain, needing to call Flush when you're
one with a buffer seems entirely reasonable and is
necessary anyway for correct execution of long-running
programs.
Even ignoring that problem, atexit introduces even more
threads of control, and you have to answer questions like
do all the other goroutines stop before the atexit handlers
run? If not, how do they avoid interfering? If so, what if
one holds a lock that the handler needs? And on and on.
I'm not at all inclined to add Atexit.
Ian Lance Taylor:
The only fully reliable mechanism is a wrapper program that invokes the
real program and does the cleanup when the real program completes. That
is true in any language, not just Go.
In my somewhat unformed opinion, os.AtExit is not a great idea. It is
an unstructured facility that causes stuff to happen at program exit
time in an unpredictable order. It leads to weird scenarios like
programs that take a long time just to exit, an operation that should be
very fast. It also leads to weird functions like the C function _exit,
which more or less means exit-but-don't-run-atexit-functions.
That said, I think a special exit function corresponding to the init
function is an interesting idea. It would have the structure that
os.AtExit lacks (namely, exit functions are run in reverse order of when
init functions are run).
But exit functions won't help you if your program gets killed by the
kernel, or crashes because you call some C code that gets a segmentation
violation.
In general, I agree with jnml's answer. Should you however still want to do it, you could use defer in the main() function, like this: http://play.golang.org/p/aUdFXHtFOM.