Member variables in method are null when called as delegate from thread
tsbockman
thomas.bockman at gmail.com
Tue Jan 12 01:49:11 UTC 2021
On Monday, 11 January 2021 at 00:43:00 UTC, Tim wrote:
> When MessageService calls the delegate for start, db is null.
> If I call start() in the Foo constructor it works just fine. Am
> I missing something here? Do delegates get called outside of
> their class context? I know I could just pass the db into start
> but I want to work out exactly why this is happening
The compiler and the physical CPU are both allowed to change the
order in which instructions are executed to something different
from what your code specifies, as long as the visible, "official"
results and effects of the chosen order of execution are the same
as those of your specified code, FROM THE PERSPECTIVE OF THE
EXECUTING THREAD.
This is allowed so that the compiler can optimize to minimize
negative "unofficial" effects such as the passage of time and
memory consumption.
However, this re-ordering IS permitted to freely alter the
behavior of your code from the perspective of OTHER threads. A
likely cause of your bug is that the write to db by the
constructor's thread is being committed to memory after the read
of db by the MessageService thread.
In order to RELIABLY fix this kind of problem, you must correctly
use the only commands which the compiler and CPU are NOT allowed
to reorder with respect to other threads, namely atomic
operations, memory barriers and synchronization primitives. A
wide selection of these tools may be found in these D runtime
library modules:
core.sync:
http://dpldocs.info/experimental-docs/core.sync.html
core.atomic:
http://dpldocs.info/experimental-docs/core.atomic.html
core.thread:
http://dpldocs.info/experimental-docs/core.thread.html
(I recommend using Adam D. Ruppe's unofficial but superior
rendering of the D runtime documentation at dpldocs.info rather
than the official dlang.org rendering, as I found some necessary
pieces of the documentation are just mysteriously missing from
the offical version.)
Be warned that most models of multi-threaded programming are
difficult to implement correctly, as opposed to ALMOST correctly
with subtle heisen-bugs. You should either stick to one of the
known simple models like immutable message passing with GC, or do
some studying before writing too much code.
Here are some resources which I have found very helpful in
learning to understand this topic, and to avoid its pitfalls:
Short educational game: https://deadlockempire.github.io/
Tech talk by C++ expert Herb Sutter (D's core.atomic uses the
C++ memory model):
https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2
https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2
If you want to seriously dig into this, I suggest reviewing some
or all of the content at the links above. If you're still
confused about how to apply it in D, feel free to come back and
ask for examples or code reviews. I'd rather not start with
examples, though, because if you don't understand the rules and
principles behind them, it's really easy to unknowingly introduce
bugs into otherwise correct examples with seemingly innocent
changes.
More information about the Digitalmars-d-learn
mailing list