Am I missing something?
--
David Roundy
Actually there is such a termination mechanism with the defer
statement : http://golang.org/doc/go_spec.html#Defer_statements
that does the same work as the c++ std::atexit() function. BTW, I see
two slight differences between defer statements and atexit function
call :
- defer is not a function, so defering mutliple statements does not
lead to mutliple function calls
- defer statement can be put in any function body.
I think you should achieve the the atexit's job by simply defering
stuff in your main function.
best regards
V.K.
I'd presume you'd do this by deferring a call to a function variable,
and then you could just modify that variable in other functions, that
wouldn't be hard.
The problem is that the deferred statements are only executed if the
program terminates without calling os.Exit, which defeats most
possible uses of the atexit system call. It really seems like a
problem that requires runtime support (or at least exposing atexit
itself).
--
David Roundy
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
done 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.
Russ
Hmmm. I wasn't aware that go wasn't intended to also be suitable for
simple short-lived programs. I had thought it was a general-purpose
programming language...
> 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
> done with a buffer seems entirely reasonable and is
> necessary anyway for correct execution of long-running
> programs.
Hmmm. I don't see how just because a feature could be abused, we
should have to put up with inferior libraries that are harder to use
properly. In particular, it'd be great to be able to use a
bufio.Writer as a drop-in replacement for other sorts of Writers. Or
to enable safer use of compress.zlib, so that compressed files would
be closed on exit.
> 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.
Hmmm. I understand there are interesting questions, but if
programmers write buggy code, I'm sure it isn't a surprise that their
code may misbehave.
> I'm not at all inclined to add Atexit.
That's unfortunate. It's reasonably simple to work around in one's
own program, simply by wrapping os.Exit, but it'd be nicer to be able
to have more robust libraries also.
--
David Roundy
I have found that the init function for modules is pretty limited. If anything fails, your only option is to panic. Therefore, you typically need a separate public function for initialization. The pattern then becomes to use defer to arrange for the termination. i.e.
err := foo.Initialize(...)
if err!=nil { ... }
defer foo.Terminate()
This does not defend against calls to os.Exit, but I would be very upset with any libraries that called os.Exit directly. Libraries should report an error condition, and not decide to abort the program. You could write your own wrapper for os.Exit, but I suspect the threading issues would be very tricky (closing resources while other goroutines are continuing to execute). Personally, I rarely use os.Exit (in C, C++, or Go) exactly because it sidesteps unwinding the stack. Russ' comments aside, I'd rather my C++ program spend a lot time needless releasing memory if I'm assured it is also properly closing files, terminating sockets, closing database handles, and generally being careful not to leave a mess.
It is not that difficult to trap panics in your go routines. These have to be dealt with accordingly, and if not, they can dumped into a channel back to your main routine. I agree that the extra code is not fun, but it also not difficult.
At the end of the day, the OP and others in the community need a pattern or idiom to arrange for clean-up when their application terminates. Do you have a better suggestion?
Russ' comments aside, I'd rather my C++ program spend a lot time needless releasing memory if I'm assured it is also properly closing files, terminating sockets, closing database handles, and generally being careful not to leave a mess.
(Yes, files and sockets will be closed by the OS when the program terminates. Will it flush the buffers? Will it ensure that the data on disk is consistent?)
Robert Johnstone writes:
> At the end of the day, the OP and others in the community need a pattern or
> idiom to arrange for clean-up when their application terminates. Do you
> have a better suggestion?
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.
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.
Just because your program can crash doesn't mean you shouldn't try to clean up after yourself and thus doesn't preclude a simple way to handle what to do when your program is exiting in some "controlled" manner.