[fpc-devel] ref count types / threadsave question

Martin Frb lazarus at mfriebe.de
Sun Jan 6 14:42:52 CET 2019


On 06/01/2019 13:19, Jonas Maebe wrote:
> On 04/01/19 00:11, Benito van der Zander wrote:
>>> Nobody is talking about the string content. 
>>
>> But when they are stored together, that is the same. You can't get 
>> one without the other.
>
> You can, since the data can be stored in a different cache line than 
> the refcount. But the principle is indeed the same: the data is not 
> guaranteed to be synchronised across cores either.

Well it is getting interesting here...

At first, it is normal that 2 threads can see different data. Same 
applies to other types (i.e. not limited to managed types).
If a thread does "SomeInt := 42", other threads may still see the 
previous values. That is ok, for all that the other threads know, the 
"some thread" may not even have reached the statement yet.

But if we look at "FreeAndNil(SomeObject)", other threads must make sure 
(synchronize ...), that they get the same value. Otherwise they access 
memory that was freed, and there is no guarantee they still see the old 
memory, never mind what happens on write access.

In any case for any variable that is split across several mem locations, 
access to the old "pointer" is dangerous, unless the programmer has 
taken care that this particular part can not change.

That means 2 threads, both accessing the same global string variable, is 
not allowed without extra protection.

The entire game only works if each thread has a separate variable 
referring the same string content (the refcount of which is then always 
 > 2, guaranteeing the referenced data remains allocated and in place).  
If one thread changes its data, it makes a copy, and the refcount goes 
to 1, and the other thread becomes sole owner)

The one thing that probably is easy to overlook, is how to give the 2nd 
thread access to the string to begin with. At that time the refcount may 
be 1, and therefore the variable for the 2nd thread must be assigned 
inside the 1st thread (the thread that owns the string). Otherwise the 
refcount could become 0, while the 2nd thread tries to get its copy.

So in that way, only the storage (and mem alloc and refcount) for 
managed variables are thread safe.
- The variable (holding the ref) is as little thread safe as any other 
var (none thread var)
- the content of a string (or dyn array) is neither thread save. s[5] 
can change in one thread, and not be known to the other. That is, if the 
refcount is 1 (which it shouldn't), or for dyn-array if the len does not 
change.

I am not sure, where (if at all) managed types and thread safety (in 
regards to refcount) is documented?
So I could not check, how well the complexity of the matter is represented.


My initial post, with the ability for the refcount to become 0 in 
between, could afaik only happen, if the 2 threads share the same 
(global) variable, and that is not thread save. (as the var could be nil 
in one thread, and outdated pointer in the other thread...)
That closes my initial question, about the ref count potentially not 
being thread safe.

------------
Btw about threads seeing different cached versions of data.
What happens in case of synchronize?

thread 1 calls Synchronize(DoFreeObject)

DoFreeObject runs in main thread: "FreeAndNil(Foo)"

Now we know that the main thread will correctly see Foo=nil.

But what will the thread 1 see?
Could the thread still see, the old value of Foo?


If so then how to I ever get a managed variable safely into a thread? 
(Once the thread was started).







More information about the fpc-devel mailing list