According to MSDN, c++/cx private destructors are “only invoked when the reference count reaches zero.”
Thus, would it be safe to say that no other threads can be manipulating an object when its private destructor is invoked?
In a nutshell, yes.
It's possible someone else could still have references to the class if they did things like cast it to a raw pointer without wrapping it in a ComPtr etc. but that's just buggy code that's going to crash sooner or later anyway.
Related
All the advice I've found on debugging memory leaks in VB6 code has focused on GDI leaks. In my situation, however, evidence suggests that I don't have a GDI leak but probably do have a memory leak. What might be some likely candidates for the cause of such a leak, and/or good tools to help me determine the portion of my program which is causing this?
Unfortunately VB6 does not have enough debugging instrumentation to detect object leaks. I'm usually implementing instance book-keeping on my own in every class, form or user control with a couple of helper functions. The basic pattern is like this
Private Const MODULE_NAME As String = "<<class_name_here>>"
#If DebugMode Then
Private m_sDebugID As String
#End If
#If DebugMode Then
Private Sub Class_Initialize()
DebugInstanceInit MODULE_NAME, m_sDebugID, Me
End Sub
#End If
#If DebugMode Then
Private Sub Class_Terminate()
DebugInstanceTerm MODULE_NAME, m_sDebugID
End Sub
#End If
Helper function DebugInstanceInit generates next sequential id and assigns it to m_sDebugID, then stores module name and ObjPtr(Me) in a collection, keyed on the id.
Helper function DebugInstanceTerm removes entry from the collection using m_sDebugID as a key.
This way in every moment of application execution you can dump this instance collection and identify count and type of objects that are allocated but still not terminated. If continuous opening and closing of forms increments object count you are leaking objects probably due to circular references (e.g. collection->entries and entry->collection).
Most frameworks and other languages have this kind of book-keeping built-in (at least in debug builds) but unfortunately VB6 has poor support for source code metadata (MODULE_NAME, FUNC_NAME, LINE_NUMBER) and object lifetime management. Lack of implementation inheritance hurts here too.
Generically, you have to watch for circular references. In VB6, an object will remain in memory as long as it is referenced somewhere. So if you have an object-type variable as a member of a form (for example) then it will be in memory until that form is Terminated (unless you explicilty set it to nother early of course). And that reference chain can be very deep:
Here, FormA is keeping ObjectB and ObjectC in memory:
FormA -> ObjectB -> ObjectC
What you need to watch for is something like this:
FormA -> ObjectB <-> ObjectC
ObjectB has a reference to ObjectC and ObjectC has a back or parent reference to ObjectB. Even if FormA is Terminated or otherwise clears it reference to ObjectB, ObjectB and ObjectC will live forever and represent a memory leak.
good tool for finding memory leaks is deleaker. you can try it. And check yet one thing - are there still GDI leak or not. You must be sure!
In my free-threaded in-proc COM object using ATL I want to add a member variable that will be set only in FinalConstruct() and read only in FinalRelease(). No other code will ever manipulate that member variable.
I doubt whether I need synchronization when accessing that member variable. I carefully read ATL sources and looks like those methods are always called no more than once and therefore from one thread only.
Is that correct assumption? Can I omit synchronization?
Yes, the assumption is correct. Think of it as an extension of the C++ constructor and destructor. In theory, you could call a method on a COM object from a different thread, while FinalRelease() is executing. Although, that is undefined behaviour, and not an expected occurrence. You shouldn't try to protect yourself from it, just as you wouldn't try to protect yourself from other threads in a destructor. If you have to protect yourself in the destructor, the design is generally broken (it would indicate that you do not have a proper termination protocol between your threads).
The only way FinalRelease() could be called from another thread, is when the client code does not have a valid reference count to your object, or if some other parts of your code is releasing twice. This is a hard error, and will probably end up in a crash anyway, totally unrelated to any synchronization errors you might have. The ATL code for managing object reference count is thread safe, and will not leave any race conditions open.
As for FinalConstruct(), a reference to the object is not returned to any client before FinalConstruct() has finished with a successful return code.
I always had this specific scenario worry me for eons. Let's say my class looks like this
public class Person {
public Address Address{get;set;}
public string someMethod()
{}
}
My question is, I was told by my fellow developers that the Address propery of type Address, is not thread safe.
From a web request perspective, every request is run on a separate thread and every time
the thread processes the following line in my business object or code behind, example
var p = new Person();
it creates a new instance of Person object on heap and so the instance is accessed by the requesting thread, unless and otherwise I spawn multiple threads in my application.
If I am wrong, please explain to me why I am wrong and why the public property (Address) is not thread safe?
Any help will be much appreciated.
Thanks.
If the reference to your Person instance is shared among multiple threads then multiple threads could potentially change Address causing a race condition. However unless you are holding that reference in a static field or in Session (some sort of globally accessible place) then you don't have anything to be worried about.
If you are creating references to objects in your code like you have show above (var p = new Person();) then you are perfectly thread safe as other threads will not be able to access the reference to these objects without resorting to nasty and malicious tricks.
Your property is not thread safe, because you have no locking to prevent multiple writes to the property stepping on each others toes.
However, in your scenario where you are not sharing an instance of your class between multiple threads, the property doesn't need to be thread safe.
Objects that are shared between multiple threads, where each thread can change the state of the object, then all state changes need to be protected so that only one thread at a time can modify the object.
You should be fine with this, however there are a few things I'd worry about...
If your Person object was to be modified or held some disposable resources, you could potentially find that one of the threads will be unable to read this variable. To prevent this, you will need to lock the object before read/writing it to ensure it won't be trampled on by other threads. The easiest way is by using the lock{} construct.
Slightly modified version of canonical broken double-checked locking from Wikipedia:
class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
// Create new Helper instance and store reference on
// stack so other threads can't see it.
Helper myHelper = new Helper();
// Atomically publish this instance.
atomicSet(helper, myHelper);
}
}
}
return helper;
}
}
Does simply making the publishing of the newly created Helper instance atomic make this double checked locking idiom safe, assuming that the underlying atomic ops library works properly? I realize that in Java, one could just use volatile, but even though the example is in pseudo-Java, this is supposed to be a language-agnostic question.
See also:
Double checked locking Article
It entirely depends on the exact memory model of your platform/language.
My rule of thumb: just don't do it. Lock-free (or reduced lock, in this case) programming is hard and shouldn't be attempted unless you're a threading ninja. You should only even contemplate it when you've got profiling proof that you really need it, and in that case you get the absolute best and most recent book on threading for that particular platform and see if it can help you.
I don't think you can answer the question in a language-agnostic fashion without getting away from code completely. It all depends on how synchronized and atomicSet work in your pseudocode.
The answer is language dependent - it comes down to the guarantees provided by atomicSet().
If the construction of myHelper can be spread out after the atomicSet() then it doesn't matter how the variable is assigned to the shared state.
i.e.
// Create new Helper instance and store reference on
// stack so other threads can't see it.
Helper myHelper = new Helper(); // ALLOCATE MEMORY HERE BUT DON'T INITIALISE
// Atomically publish this instance.
atomicSet(helper, myHelper); // ATOMICALLY POINT UNINITIALISED MEMORY from helper
// other thread gets run at this time and tries to use helper object
// AT THE PROGRAMS LEISURE INITIALISE Helper object.
If this is allowed by the language then the double checking will not work.
Using volatile would not prevent a multiple instantiations - however using the synchronize will prevent multiple instances being created. However with your code it is possible that helper is returned before it has been setup (thread 'A' instantiates it, but before it is setup thread 'B' comes along, helper is non-null and so returns it straight away. To fix that problem, remove the first if (helper == null).
Most likely it is broken, because the problem of a partially constructed object is not addressed.
To all the people worried about a partially constructed object:
As far as I understand, the problem of partially constructed objects is only a problem within constructors. In other words, within a constructor, if an object references itself (including it's subclass) or it's members, then there are possible issues with partial construction. Otherwise, when a constructor returns, the class is fully constructed.
I think you are confusing partial construction with the different problem of how the compiler optimizes the writes. The compiler can choose to A) allocate the memory for the new Helper object, B) write the address to myHelper (the local stack variable), and then C) invoke any constructor initialization. Anytime after point B and before point C, accessing myHelper would be a problem.
It is this compiler optimization of the writes, not partial construction that the cited papers are concerned with. In the original single-check lock solution, optimized writes can allow multiple threads to see the member variable between points B and C. This implementation avoids the write optimization issue by using a local stack variable.
The main scope of the cited papers is to describe the various problems with the double-check lock solution. However, unless the atomicSet method is also synchronizing against the Foo class, this solution is not a double-check lock solution. It is using multiple locks.
I would say this all comes down to the implementation of the atomic assignment function. The function needs to be truly atomic, it needs to guarantee that processor local memory caches are synchronized, and it needs to do all this at a lower cost than simply always synchronizing the getHelper method.
Based on the cited paper, in Java, it is unlikely to meet all these requirements. Also, something that should be very clear from the paper is that Java's memory model changes frequently. It adapts as better understanding of caching, garbage collection, etc. evolve, as well as adapting to changes in the underlying real processor architecture that the VM runs on.
As a rule of thumb, if you optimize your Java code in a way that depends on the underlying implementation, as opposed to the API, you run the risk of having broken code in the next release of the JVM. (Although, sometimes you will have no choice.)
dsimcha:
If your atomicSet method is real, then I would try sending your question to Doug Lea (along with your atomicSet implementation). I have a feeling he's the kind of guy that would answer. I'm guessing that for Java he will tell you that it's cheaper to always synchronize and to look to optimize somewhere else.
I have a class which is a descendant of TThread. I have some public properties that are read only. Will I run into problems if my main thread reads those values while the thread is active?
If by "read-only properties" you mean the TThread descendant itself doesn't ever change them either, and initializes them a.s.a.p, then no, everything will be fine (as long as you make sure the thread is alive and kicking whenever you request the property values).
If by "read-only properties" you mean the TThread descendant will be the only one changing them, you will want to make sure the main thread isn't reading them while they are being changed (unless they are atomic values, like integers).
The basic types, like Integer, Boolean, Char, and Pointer, are safe to read at any time. Reference types, like string, interfaces, and dynamic arrays, are safe to read only if there's no chance the other thread could be assigning a new value at the same time. Use a critical section or the Synchronized method, for example, to make sure the thread isn't modifying the value while the main thread is reading from it.
You also have to remember that any value you read may be out of date by the time you use it — the thread might have written a new value between the time you read it and the time you use it.
That depends on the property types and possibly on their accessor methods.
type
TMyThread = class(TThread)
private
FIntfield: integer;
public
property IntField: integer read FIntField;
end;
Accessing this property won't be a problem since accessing 32 bit values is an atomic operation. But if the property is larger than 32 bit or a class reference that might be changed while the main thread accesses it, you will run into trouble.