Recent

Author Topic: Interfaces and Reference Counting  (Read 3773 times)

JimKueneman

  • Full Member
  • ***
  • Posts: 178
Interfaces and Reference Counting
« on: January 21, 2017, 05:00:20 pm »
I am seeing behavior with reference counting that is causing me a problem.  It seems whenever I use the "as" operator in a function the compiler is increasing the reference count by 2 for the first time the operator is used.  It seems like it is assigning the interface to the local interface plus adding one "just in case".  This works just fine in normal functions as when it exits the function the reference is decremented by the 2.

Now the rub.  I am using interfaces in threads.  When I use the "as" operator in the thread the reference count is incremented by 2 but that is not acceptable since I will never exit the thread function until the thread ends.  That causes all my interfaces to be held in limbo until the application ends.

Is this a known problem or am I not debugging this correctly?

Thanks,
Jim

Thaddy

  • Hero Member
  • *****
  • Posts: 10293
Re: Interfaces and Reference Counting
« Reply #1 on: January 21, 2017, 05:06:09 pm »
Can you add a rudimentary example that has this behavior? Pref. fpc only? Need to compare this to Delphi behavior too, btw.

The reason is that the As modifier is like asking for a new reference. So in principle the behavior is correct.
If Delphi doesn't have the same behavior, I want to see how it behaves in such cases.

Are you mixing class instantiated instances with interface instantiated instances?
That may also be the cause of your problems.
« Last Edit: January 21, 2017, 05:13:17 pm by Thaddy »
I am more like donkey than shrek

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 751
Re: Interfaces and Reference Counting
« Reply #2 on: January 21, 2017, 05:25:02 pm »
When exactly reference counts are increased or decreased is implementation-dependent, and not something your code should rely on. In some cases FPC releases reference counted objects earlier than Delphi (e.g. http://bugs.freepascal.org/view.php?id=26602 ), in other cases it's later (as in this case, which is extensively discussed in http://bugs.freepascal.org/view.php?id=9472 ).

When exactly a reference count is decreased is a matter of code generation and optimization. You cannot make any assumptions about it. Even in Delphi depending on the situation it may take longer to release it.

JimKueneman

  • Full Member
  • ***
  • Posts: 178
Re: Interfaces and Reference Counting
« Reply #3 on: January 21, 2017, 05:40:04 pm »
Well I made an example but the example in the bug report is the same.  Seems like a lot of opinions on the behavior so I think the reason I wanted to use reference counting is not the way to do it with the built compiler.  I will implement my own reference counting to do what I want.

Thanks

Thaddy

  • Hero Member
  • *****
  • Posts: 10293
Re: Interfaces and Reference Counting
« Reply #4 on: January 21, 2017, 05:42:39 pm »
I took part in that discussion.
But anyway: the behavior in the case of threading is of particular interest to me.
So if OP can add a simple clean example that replicates this we can find out more in the context of threading, not in the context of release implementation.
Maybe there is a simple way to mitigate this.
I am more like donkey than shrek

Thaddy

  • Hero Member
  • *****
  • Posts: 10293
Re: Interfaces and Reference Counting
« Reply #5 on: January 21, 2017, 05:49:04 pm »
Well I made an example but the example in the bug report is the same. 
No it is not:
The example in the bug report does not use threading and that bug report has lead to changes in the compiler behavior as per the last remark by Vincent.
IOW it is not representative for the current compiler.
In a non-threaded environment you should not run into trouble unless you make assumptions about the implementation.
In the context of threading, this was never considered. So that's a new issue, unless you insist that the example from the bug report is sufficient to demonstrate your issue.
In that case: threading was never the issue.
« Last Edit: January 21, 2017, 05:58:20 pm by Thaddy »
I am more like donkey than shrek

JimKueneman

  • Full Member
  • ***
  • Posts: 178
Re: Interfaces and Reference Counting
« Reply #6 on: January 21, 2017, 06:28:57 pm »
Well my example did not have have the thread.  It was just an example that showed how the reference counting was done and it was just a simple thought experiment to make the jump to how the threaded example would be a problem.  What I am doing is simple so I will just explain it.

For now I create an interfaced object in the main thread.  I have this structure:

Code: Pascal  [Select][+][-]
  1. TDynamicArrayInterface = array of IUnknown;
that is wrapped by an object to implement thread safe locking of access to this array.

I create an object that descends from IInterfacedObject and my own custom interface

In the main thread I add these object to the list (I known about the mixing of object and interface problems).  I then have a thread running that grabs these items out of the list in parallel.

In the thread I need to cast the IUnknown objects to IMyInterface objects and pass them around to other threads.  That is why I wanted them in the first place.  Instead of making N copies of the object I would just pass the same object around and when everyone was done with them they would be freed automatically.  That is where the double reference increase fails me.  Like I said the double increase is fine if done within a function because on exit of the function this decremented correctly but when it is done in a thread the thread never returns  so that extra reference increase never get decremented and the object will have N * Number of Threads that where passed the object references remaining when it should be allowed to be freed.

The discussions in the bug report are exactly what is happening with the one extra dynamic of the thread never returning so the double reference increase is never fully decremented and the object is never freed.

I do this as a hobby and am in no way informed enough to add any input as to if the current implementation is right, wrong or indifferent. 

Thanks,
Jim

JimKueneman

  • Full Member
  • ***
  • Posts: 178
Re: Interfaces and Reference Counting
« Reply #7 on: January 21, 2017, 06:32:46 pm »
After writing that I also realized that my object is not thread safe and doing this will actually cause me other problems so I will need to make copies of the objects for the threads anyway so I may be pulling out the interfaces in the near future anyway.

Thaddy

  • Hero Member
  • *****
  • Posts: 10293
Re: Interfaces and Reference Counting
« Reply #8 on: January 21, 2017, 08:55:33 pm »
The current behavior is such that if the thread runs uninterrupted the refcount is the same as before the thread started.
The refcount increase by 2 is caused by a necessary temp variable that keeps the reference alive/locked while doing internal processing.
This is explained by Florian in the bug report and has changed slightly over the years: release when scope ends is earlier/quicker,also earlier/quicker than Delphi.
But in some cases this is different as Jonas explained.
If you do not use something like KillThread I can't find an issue.
I am more like donkey than shrek

Thaddy

  • Hero Member
  • *****
  • Posts: 10293
Re: Interfaces and Reference Counting
« Reply #9 on: January 21, 2017, 09:00:07 pm »
After writing that I also realized that my object is not thread safe and doing this will actually cause me other problems so I will need to make copies of the objects for the threads anyway so I may be pulling out the interfaces in the near future anyway.

In trunk there is TThreadList<T> to maybe solve that issue. T can be an interface. You will find it in rtl-generics
« Last Edit: January 21, 2017, 09:06:39 pm by Thaddy »
I am more like donkey than shrek

 

TinyPortal © 2005-2018