Skip to content
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

Closed
ben-craig opened this issue Jul 22, 2016 · 5 comments
Closed
Assignees

Comments

@ben-craig
Copy link

The footnote about deadlocks for thread-safe statics is confusing. Here's the relevant text from the draft standard:

6.7 Declaration statement [stmt.dcl]
4  [...] If control enters the declaration concurrently while 
the variable is being initialized, the concurrent execution 
shall wait for completion of the initialization. (92) [...]

92) The implementation must not introduce any deadlock
around execution of the initializer

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.

@jwakely
Copy link
Member

jwakely commented Jul 22, 2016

"The implementation must not introduce any deadlocks around execution of the initializer that are not implied by the program semantics"

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."

@ben-craig
Copy link
Author

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.

@jensmaurer
Copy link
Member

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?

@ben-craig
Copy link
Author

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.

@jensmaurer jensmaurer changed the title Thread-safe statics "deadlock" footnote causing confusion. [stmt.dcl]/4 Thread-safe statics "deadlock" footnote causing confusion. Dec 16, 2016
@jensmaurer
Copy link
Member

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants