Member variables in method are null when called as delegate from thread
Tim
t.oliver at windowslive.com
Wed Jan 13 02:15:49 UTC 2021
On Tuesday, 12 January 2021 at 01:49:11 UTC, tsbockman wrote:
> 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.
Fantastic response, thank you! I did some more digging and
properly narrowed down where the issue is and created a test
script that demonstrates the problem. Let me know what you think
and if it could still be a similar problem to what you have
stated above. I'll still read that info you sent to sharpen up on
these concepts.
Basically, the program calls a function which modifies a document
in the database. If it is called form it's own class'
constructor, it works fine. If it is called by a thread, it never
returns. I don't think that a member variable is going null or
anything. But a strange problem that I can't seem to debug. The
output is at the bottom.
----------------------------------------------------------------
import vibe.db.mongo.mongo;
import core.thread;
import std.stdio;
void main(){
auto callable = new Callable();
while(true){}
}
class Caller : Thread{
void delegate() mFunc;
this(void delegate() func){
mFunc = func;
super(&loop);
start();
}
void loop(){
while(true){
mFunc();
}
}
}
class Callable{
MongoClient db;
Caller caller;
this(){
db = connectMongoDB("127.0.0.1");
foo();
caller = new Caller(&foo);
}
~this(){
db.cleanupConnections();
}
void foo(){
writeln("Started");
auto result =
db.getCollection("test.collection").findAndModify([
"state": "running"],
["$set": ["state": "stopped"]
]);
writeln(result);
writeln("Finished");
}
}
----------------------------------------------------------------
Output:
Started
{"_id":"5ff6705e21e91678c737533f","state":"running","knowledge":true}
Finished
Started
More information about the Digitalmars-d-learn
mailing list