Is there anything like Java Memory Model in Delphi? To prevent misunderstandings: I mean nothing like "huge/large/small", but the things related to visibility of changes to other threads.
-
"The Java Memory Model (...) makes it possible to reason about code execution in a multithreaded environment, even in the face of optimizations performed by the dynamic compiler, the processor(s) and the caches." (from your linked page). - A [QC](http://qc.embarcadero.com/) entry would be interesting – mjn Oct 16 '12 at 15:25
-
There's no official documentation. Memory model is that of the underlying hardware. The only thing you need to take care over is whether or not compiler optimises variables into registers. I think it can do this for local variables, but never does so for other types of variables. But I'm not sure. Would be nice if someone like Allen Bauer who actually knows the answer could put us out of our ignorance. – David Heffernan Oct 16 '12 at 16:00
-
2@David Heffernan: If things were that simple, there'd no need for a memory model. The amd64 architectures makes no guarantee for normal memory access without special instructions. On a multicore system, there's no guarantee that a thread will *ever* see *any* changes made *in memory* by a thread running on a different core, unless you're using `volatile` or doing some synchronization. This actually happens and it's quite common. – maaartinus Oct 16 '12 at 17:17
-
Delphi doesn't have volatile. So I don't know what you are talking about. And the x86 and x64 hardware do make guarantees. There is a defined hardware memory model. – David Heffernan Oct 16 '12 at 17:20
-
I've never said Delphi had [volatile](http://en.wikipedia.org/wiki/Volatile_variable), but it's an old and well-known concept. The existing guarantees made by Intel/AMD are week and getting even [weaker](https://blogs.oracle.com/dave/entry/java_memory_model_concerns_on). – maaartinus Oct 16 '12 at 17:42
-
1x86 and x64 have strong memory models: http://herbsutter.com/2012/08/02/strong-and-weak-hardware-memory-models/ As for `volatile`, I know it well, although it has many different meanings depending on what compiler you use. But since you are talking about Delphi, it has no meaning here. My understanding is that Delphi makes non-local variables volatile, for some appropriate definition of volatile! – David Heffernan Oct 16 '12 at 17:53
-
2If Intel/AMD "weaken" the existing memory model for x86/x64 instruction sets, every app and OS on the planet will break. They can only "weaken" memory semantics on new instructions or new execution modes that existing code and compilers don't use. Intel and AMD understand "opt in" very well. – dthorpe Oct 16 '12 at 18:27
-
@dthorpe Do you have anything more to offer here? I know you've been away from the compiler for some time now, but I'm sure it's policies in this arena have not changed. – David Heffernan Oct 16 '12 at 18:30
-
1I can't comment on current Delphi compiler stuff, but I can be pretty adamant about Intel/AMD hardware. :> – dthorpe Oct 16 '12 at 18:33
-
1@dthorpe Could you comment on D6 compiler? I know that the current 32 bit compiler is pretty much indistinguishable in this arena. – David Heffernan Oct 16 '12 at 18:42
-
1*visibility of changes to other threads* - don't exchange pointers and use `threadvar` and it would look kinda the same – Arioch 'The Oct 17 '12 at 07:53
1 Answers
I'd say the Delphi memory model matches the C++ memory model. That is, the compiler is not aware of multiple processes or multiple threads and does not provide any special support for those scenarios. See "What is the C++ memory model for concurrency?"
The Delphi 32 bit compiler does perform optimizations such as invariant code motion and does emit instruction sequences designed to avoid stalling dual pipelines. However, the Delphi compiler does not contain an instruction scheduler or peephole optimizer, so opportunities for instruction reordering are slim to none. Delphi optimizations occur on the AST / IR before instruction emit.
Local variables may be enregistered, but any source code reference to a variable that requires a memory address (such as passing a local variable to a var param, or taking the address of a local var) will force the compiler to commit the enregistered value to a memory location prior to use of the address, or may force the compiler to completely abandon enregistering the variable at all.
The Delphi 32 bit compiler is fairly conservative in its optimizations. The biggest performance gains from optimizations are from enregistering variables and intermediate results, and from various loop induction tricks.
Operations on global symbols or symbols residing in global memory (such as object fields) are not enregistered. There is no "volatile" modifier.
The compiler codegen patterns rely on the x86 architecture rules that register-sized writes to global memory at aligned addresses are atomic. Writing of large data, byte data, or at unaligned addresses may cross a cache line and require two separate write operations within the single write instruction. The Delphi compiler is (mostly) oblivious to this.
Regardless, if you are writing Delphi code that accesses shared memory from different threads, it is always your responsibility to decide what thread synchronization measures are appropriate to your situation and implement them.
-
2+1. Danny, that was an extremely well written answer. Nicely done! One of the rare occasions I've wished I could upvote more than once. – Ken White Oct 17 '12 at 02:30
-
1+1, really nice answer. I'd like to know if there are any plans/intentions to improve Delphi's memory model regarding processes and threads, though. Btw, anyone knows if the 64-bit compiler works the same way? – Guillem Vicens Oct 17 '12 at 06:13
-
2Thanks for this. Regarding 64 bit, @Guillem, from what I have seen it adopts the same strategy for enregistering. – David Heffernan Oct 17 '12 at 06:44
-
1I can't speak to plans or intentions. I've been out of the loop since 2005. – dthorpe Oct 17 '12 at 17:08