0

I implementing a high performance thread safe component, using no lock statements, only volatile and Interlocked are used for performance reasons.

I have volatile reference-type member in a class, that contains thread safe instance. This instance is thread safe only for a couple of operations, and not for another. Because of that and for performance reasons, in some cases i prefer creating new instance instead of updating the original, and it really working faster, especially because i dont using any lock statements.

So the volatile member can be replaced in any time to another instance, the volatile keyword ensures that there will not be any problem with that in multithreaded environment.

This of course working very well, but the only problem with that is the garbage collection of the old instances. When tested my component for performance, i found that it spending too much time in garbage collection the released instances.

Now i searching a way to recycle the old instances. The problem is that i can't just take the old instance when replacing and just reset it's state because there may be another threads that still using this instance and i can't found a way (without lock) that guaranties that noone using this instance anymore.

How can i guaranty that there is no thread that using the old instance without lock statements? (volatile and Interlocked are preferred)

Thanks.

DxCK
  • 4,402
  • 7
  • 50
  • 89
  • 3
    does using lock really decreases performance significantly? – ironic Dec 22 '09 at 22:37
  • I really like that word "determinate", going to have to remember that one. – Mark Ransom Dec 22 '09 at 22:51
  • 1
    If you need that fine grain control over memory management, a managed application is probably not the right way to go. What are you doing where you lock is a performance penalty? – GrayWizardx Dec 22 '09 at 22:56
  • @ironic: when using lock, you are loosing one of the most important advantage of multithreading because all requests are processed synchronous despite the threads, like you're using only one thread. In my tests on dual core machine i found that using no locks are faster x10 times for my component. GC is the next bottleneck i want to pass for full efficiency and to support close-to-real-time applications in C#. – DxCK Dec 22 '09 at 23:04
  • 1
    "when using lock ... all requests are processed synchronous" -> you were doing/understanding something very wrong. – H H Dec 22 '09 at 23:44
  • @DxCK - the same is true for accessing volatiles. Also I doubt you can see the real impact of the locks on a dual core box - unless whatever you are doing under the lock is really heavy and, especially if it involves IO. If this is the case, might be a better approach is to go back to the locks but optimize (minimize) what you are doing there – mfeingold Dec 22 '09 at 23:58
  • What data is stored by the objects you refer to? How often is each piece of data altered? What logic are they performing? If you provide more detail, it may be easier to provide solutions. – Phil Jan 02 '10 at 07:53

4 Answers4

2

What you are trying to implement here looks so much like reference counting (remember COM?). You probably can do this with increments / decrements - just keep a reference counter right next to your reference.

The only problem with this technique is that it relies on the object consumers to be decent with object usage. This makes the code very fragile.

Another question is that AFAIK the main performance problem with locks is not the lock iteself but rather the memory barrier it implies. The point is that every acces to a volatile variable does the same. In other words I do not thnk you gained anything replacing locks with volatile variables

mfeingold
  • 7,094
  • 4
  • 37
  • 43
  • I thought about counting, but the problem is that take a reference and increment a counter can't be an atomic operation, so this can create race condition in case that a thread just took a reference and not incremented the counter yet, another thread finds that the counter is zero and recycling the instance while the previous thread incrementing the count and doing other stuff. – DxCK Dec 22 '09 at 23:18
  • It's not true that access to volatile implies a barrier, assuming that volatile has the same semantics in the C# memory model as Java - processors such as all x86 CPUs have strong enough memory visibility semantics that *read* access to a volatile needs no special semantics at the CPU level - only writes need a barrier/interlocked instruction (of course at the bytecode level both reads and writes have special semantics wrt allowed re-orderings and so on). – BeeOnRope Dec 23 '09 at 00:43
1

The problem is that any thread can take a reference to object onto the stack, and then do whatever they want with it. There's no way of preventing this for the non-threadsafe operations without using an overall lock.

Generally, you shouldn't try to work against the .NET garbage collector - it'll be better to find out why GCs are taking so long, and optimize for that (don't create so many instances in the first place, maybe an O(n^2) operation creating lots of instances?) rather than trying to re-use instances in a thread-safe way.

thecoop
  • 45,220
  • 19
  • 132
  • 189
  • the many instances are created by design, it should be like that. if i could recycle the instances so no garbage collection will be needed at all. – DxCK Dec 22 '09 at 22:45
0

You are asking if something exists that will tell you if it is safe to do an operation on an object in a multi-threaded application. That is the definition of a lock. If using the structure that is provide by .NET is not fast enough, maybe you should consider changing to a complied language that will run faster.

unholysampler
  • 17,141
  • 7
  • 47
  • 64
  • i want to recycle because i dont want to use lock from the first place for performance reasons. i dont asking to completely synchronize access to an instance, i just want to wait until all others are done with the instance and then do whatever i want with it, this definition is less generic than the original lock definition and i'm sure i can be done without lock. – DxCK Dec 22 '09 at 22:52
0

You could ressurect the object from the dead, i.e. when your objects are finalized you actually make them alive again. This has the benefit, that at this point in their lifecycle, there cannot be any reference to them, otherwise they would have never been applicable for finalize in the first place. For more details look for the "Ressurection" chapter in this article.

Now, if that really buys you any performance, or if it is worth doing it, I can't tell ;-)

Christian.K
  • 47,778
  • 10
  • 99
  • 143