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
[stmt.dcl]/4 Thread-safe statics "deadlock" footnote causing confusion. #849
Comments
I don't think that's clearer personally. As a frequent reader of standardese, "the implementation must not introduce" already means that it's not talking about deadlocks caused by the programmer. Furthermore, the implementation doesn't introduce deadlocks implied by the program logic, the programmer does. How about adding a second sentence, rather than extending the first? e.g. "The implementation must not introduce any deadlocks around execution of the initializer. This does not preclude deadlocks being caused by the program logic; the implementation need only avoid deadlocks due to its own synchronization operations." |
I'm not particularly attached to my rewording. I don't really like the extra sentence you added either though. I think that sentence has about as much subtlety as the original foot note, and I want to reduce the subtlety. As a programmer, I need to know what locks are in the system so I can manage my lock hierarchy correctly. The standard implies behavior here, but I would much prefer that the behavior be stated more directly, even if that is just in some non-normative note or example. I think what I'm looking for is a more obvious statement as to the locking behaviors that are permitted by the standard. The standard permits a per-object lock around initialization, and it permits implementations that simulate a per-object lock. The standard doesn't permit a single global lock. |
I was under the impression that the standard does allow a singe global recursive mutex for statics. Which situation would come up with that where the deadlock rule is violated? |
Suppose I have my own global mutex. In thread 1, I lock my mutex, then call into a function with a function-level static of type Foo (my_foo). In thread 2, I call into a function with an independent function-level static of type LockedFoo (my_locked_foo). The constructor of LockedFoo grabs the global mutex. If the construction of my_foo and my_locked_foo are both guarded by the same global recursive mutex, then you get a deadlock. If they have (effectively) different mutexes, then you don't have a deadlock. This deadlock isn't implied by the program semantics. |
@ben-craig: Thanks for the explanation. Since the standard is a specification, we try not to preclude novel implementations that nobody thought about before. So, I do like @jwakely additional sentence (slightly refurbished) instead of expressly talking about specific locking techniques. |
The footnote about deadlocks for thread-safe statics is confusing. Here's the relevant text from the draft standard:
The footnote can be (mis) interpreted to mean that the synchronization objects guarding thread safe statics can not participate in a deadlock.
It is my understanding that this footnote was added to prohibit an implementation that uses a single global recursive mutex to guard all statics. Stated in a different way, the language has added some deadlocks, but the implementation is not permitted to add any deadlocks beyond those that the language has already added.
A few possible ways to fix this wording issue:
Clarify the footnote so that it doesn't suggest a total lack of deadlocks.
"The implementation must not introduce any deadlocks around execution of the initializer that are not implied by the program semantics"
Remove the footnote.
Discussion on the clang-dev mailing list on this issue can be found here.
The text was updated successfully, but these errors were encountered: