New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: define how finalizers interact with memory model #9442

Open
dvyukov opened this Issue Dec 25, 2014 · 3 comments

Comments

Projects
None yet
3 participants
@dvyukov
Member

dvyukov commented Dec 25, 2014

Finalizers introduce concurrency, but the synchronization between goroutines accessing the object and the finalizer are not defined. The proposed wording is along the lines of "SetFinalizer happens before execution of the finalizer starts". This makes the following program correctly synchronized:
http://play.golang.org/p/arA1niVAZC
However, the following program contains a data race on x.y and *x.y:
http://play.golang.org/p/cpuvxDu6AW
The program indeed can be compiled in a way that makes the panic to fire. Namely, compiler reorders "x.y = &i" and "*i = 42". This result can be unexpected.

@ianlancetaylor ianlancetaylor added this to the Go1.5 milestone Dec 27, 2014

@rsc rsc removed the release-none label Apr 14, 2015

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Jul 24, 2015

I know there is a certain amount of confusion at present about SetFinalizer, but I'm not sure your proposal is strong enough. I think that this program is race free:
http://play.golang.org/p/WdFVb3p7du

In words, if I have a pointer, then the pointer can not be finalized while I'm in the process of using it to assign a value. That is stronger than merely saying that SetFinalizer happens before the execution of the finalizer.

One possibility would be "given a pointer p, any read or write of *p happens before p's finalizer is run." But that is too strong, as it prohibits the compiler from reordering any operation across the use of a pointer.

I feel like what we want here is an inverse relationship. Given a pointer p, there is no possible ordering such that the finalizer happens-before any read or write of *p. But I don't know if that makes any sense.

@ianlancetaylor ianlancetaylor modified the milestones: Unplanned, Go1.5 Jul 24, 2015

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Jul 24, 2015

Moving to unplanned.

@dvyukov

This comment has been minimized.

Member

dvyukov commented Jul 24, 2015

One possibility would be "given a pointer p, any read or write of *p happens before p's finalizer is run." But that is too strong, as it prohibits the compiler from reordering any operation across the use of a pointer.

Indeed. Also if you have p.f.foo(), you generally don't know whether you access *p or **p and that can change over time. So a guarantee only for *p becomes too subtle to be used reliably. I also suspect there are more optimizations it prohibits as it effectively makes almost any store a synchronization operation. Also, if I just load from an object, but they result is eventually unused, does it order finalizer?

FWIW Java makes exactly the guarantee I described.

I feel like what we want here is an inverse relationship. Given a pointer p, there is no possible ordering such that the finalizer happens-before any read or write of *p. But I don't know if that makes any sense.

It makes sense, but it states effectively what I proposed :)
If a finalizer can't happen-before, then it happens either after or concurrently. But if it potentially can happen concurrently, then you need to synchronize accesses to prevent data races.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment