You are not logged in.
Pages: 1
about thread concurrency with Delphi
function Dummy: integer;
var
A
B
C
begin
//do something
end;
Then suppose to have many threads calling Dummy()
the local variables A,B,C instance are unique globally or instantiated for each thread? Are there some runtime management?
The access to those variables are atomically done if global unique or we should use a critical section before use Dummy()?
So what happens in RAM when two threads are calling Dummy concurrently and accessing read/write ABC at the same time?
thanks for info
Offline
1. Every thread has it's own stack (usually 1 MB, but can be changed). Every variable(of a method) of basic types/records/static arrays is allocated on stack (it's private space of that thread).
2. You can't make a read-modify-write of global variable without CriticalSection because it not atomic operation (is 3 operations) and a thread switch can happen exactly between those 3 ops. So you can't make index := Inc(index) without CS.
3. Let's say you only want to write to an integer(32 bit) in multiple threads without protecting with a CS. It is an atomic operation as long as memory manager align memory addresses to at least 32bit. If you write an Int64 from multiple threads and memory is aligned 32bit you can have bad results (it's not atomic).
4. If you decide to use point 3. (write integer, with memory aligned 32 bit, without CS) you must know that operations executed are not in the order you elaborated in your program, but are executed in a different order because of optimizations in L1 cpu cache. If you need exact order you must protect with a memory barrier. CriticalSection, SRW, InterlockedIncrement, etc .. they all have memory barrier.
5. Programming without LOCK is an super-expert task. Optimize your algorithm so you minimize the number of LOCK (don't allocate strings - work with a buffer, reuse the same instance many times, etc). And when you have to LOCK use InterlockedIncrement, InterlockedExchange, etc... They are the slimmest type of LOCK (on modern cpu is one instruction). If you need more, use CriticalSection or SWR (Vista+)..they are also implemented with InterlockedIncrement, but if the LOCK is taken by another thread they degrade successfully to kernel WaitForSingleObject. You can use InitializeCriticalSectionAndSpinCount so the CS makes like 4000(as many as you want) round-trip instruction trying to acquire the lock, before degrades to much heavier WaitForSingleObject which makes the same thing. For small and fast locks this spin count try is a huge improvement.
Last edited by emk (2017-09-09 15:16:15)
Offline
So, let's say, in a method the local variables are allocated in the stack every time the funcion is called (and the manager deallocate them at the function exit), so doesn't need to be protected from other threads (every thread get a copy of the vars in the stack), allright?
Instead all global types obviously should be protected from read/write using monitor, mutex, crts...
Offline
Yes, in a method, all local variables are independent from other threads.
Simple types, integer, boolean, etc are allocated directly on stack. A string is allocated dynamically on heap (which is global space, because a string in Delphi can be like 2GB) and also on current private stack is allocated a pointer to that global space, so only the current thread "knows" the location of that string allocated on global memory. So it's thread safe.
But what I tried to explain in previous post is every time you modify a string, an allocation on heap is made(almost every time), what means other CPU cores are blocked, so that current CPU core can claim a memory space for that string. That induces a lot of LOCKs which degrades performance. That's why mORMot is so fast because is trying to prevent those dynamic allocations . If your server app is not very intensive or serves only dozens of users, ignore my comment about performance.
Global variables must be protected.
Offline
thanks for the info
Offline
Pages: 1