-
Notifications
You must be signed in to change notification settings - Fork 48
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
Cherry-pick: ICU-21591 Release lock in SimpleDateFormat::tzFormat in case of failure #101
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, thanks @daniel-ju! 😊
// | ||
// Once initialized, no const function can modify fTimeZoneFormat, | ||
// meaning that once we have safely grabbed the other.fTimeZoneFormat | ||
// pointer, continued synchronization is not required to use it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't adoptTimeZoneFormat/setTimeZoneFormat modify the value and make it invalid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Hui.
If I understand correctly, I think what you are saying is that calling adoptTimeZoneFormat
/setTimeZoneFormat
will delete the existing object and modify fTimeZoneFormat
as well. However, the delete and modify might not happen at the same time -- so there is a possible risk that the assignment operator might see this intermediate state.
So I think the question is if adoptTimeZoneFormat
/setTimeZoneFormat
should use a Mutex lock as well?
However, IIRC, I think the design pattern for ICU objects is that they can only be used in a multithreaded context when only const
methods are called.
https://unicode-org.github.io/icu/userguide/icu/design.html#thread-safe-const-apis
However, you cannot use a reference to an open service object in two threads at the same time if either of them calls any non-const API. An individual open service object is not thread-safe for concurrent “writes”. Rather, for non-const use, you must use the clone function to create a copy of the service you want and then pass this copy to the second thread. This procedure allows you to use the same service in different threads, but avoids any thread synchronization or deadlock problems.
In otherwords, you're supposed to first create the object, mutate it as needed, and then you can share it with multiple threads, as long as they only call const
methods on it. So it would be an error if any of the threads called a non-const method.
I think the reason why this was an issue with tzFormat
is because it is declared const
, but it does mutate the object (by lazy creating the fTimeZoneFormat
member).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Jeff for the explanation! So adopt/set is not a concern. But for any reader of fTimeZoneFormat, it's still not thread safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Hui!
Can you expand a bit more on what the remaining thread safety issue is?
IIUC, I think the pattern is such that changes/mutations should only happen in one thread, so there shouldn't be simultaneous readers of fTimeZoneFormat
while it is being changed.
[Also, FWIW, this change is just a cherry-pick of an upstream fix. But if there's more changes that are needed we could file an additional bug(s) as needed.]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just like what's fixed for operator=, one can have another thread trying to do: localFormat = globalDataFormat.fTimeZoneFormat. Wouldn't it have the same issue fixed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, fTimeZoneFormat is private. so i guess it's ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but fTimeZoneFormat
is a private member, so other threads shouldn't be able to access it directly. In terms of class methods, other than the constructors/destructor, the only readers that I see which access the fTimeZoneFormat
variable are operator=
, adoptTimeZoneFormat
, setTimeZoneFormat
, and tzformat
.
The change cherry-picked in this PR adds a lock to operator=
and tzformat
, so that just leaves adopt/setTimeZoneFormat, but those methods are non-const, so they shouldn't be used in a multithread context -- so I'm not sure what else is left? (Maybe I am just missing something silly/simple though. :) )
Summary
This cherry-picks the upstream fix to resolve the deadlock in
SimpleDateFormat::tzFormat
.Upstream ticket: https://unicode-org.atlassian.net/browse/ICU-21591
Upstream PR: unicode-org/icu#1701
PR Checklist