Weird thread parameter problem
-
I have a ATL class with one member function. If i invoke a thread from the member function passing the 'this' pointer as the CreateThread() parameter the data is invalid when the parameter is casted back inside the thread function. A test app demonstrating the problem is available on http://www.codeit.dk/christian/threadtest.zip Like this // This is my member function which // is invoked from within my vb test app STDMETHODIMP Cxx::yy() { DWORD dwID=0; // I put some data into a member variable m_dwFoo = 200873; ::CreateThread(NULL, 0, _TheThread, (LPVOID)this, 0, &dwID); return S_OK; } static DWORD WINAPI _TheThread(LPVOID lpv) { // Cast the lpv pointer back to a class instance // (the this pointer) Cxx* p = (Cxx*)lpv; // Now p->m_dwFoo is corrupted with an invalid value!! return 0; } If I invoke the thread method from within 'OnFinalConstruct()' everything is peachy. It only happens when it is invoked from within a exposed automation method. The class is declared a free-threaded in the registry. Any clues? Christian Skovdal Andersen
-
I have a ATL class with one member function. If i invoke a thread from the member function passing the 'this' pointer as the CreateThread() parameter the data is invalid when the parameter is casted back inside the thread function. A test app demonstrating the problem is available on http://www.codeit.dk/christian/threadtest.zip Like this // This is my member function which // is invoked from within my vb test app STDMETHODIMP Cxx::yy() { DWORD dwID=0; // I put some data into a member variable m_dwFoo = 200873; ::CreateThread(NULL, 0, _TheThread, (LPVOID)this, 0, &dwID); return S_OK; } static DWORD WINAPI _TheThread(LPVOID lpv) { // Cast the lpv pointer back to a class instance // (the this pointer) Cxx* p = (Cxx*)lpv; // Now p->m_dwFoo is corrupted with an invalid value!! return 0; } If I invoke the thread method from within 'OnFinalConstruct()' everything is peachy. It only happens when it is invoked from within a exposed automation method. The class is declared a free-threaded in the registry. Any clues? Christian Skovdal Andersen
Hiya, at first - Visual Basic only supports Apartment-model even if "free threaded" is preferred in registry. When you create additional threads in your COM app, care must be taken when calling any methods/events from that threads. Without looking into sample code, i would guess the apartment instance pointer, your 'this' must be wrapped/marshalled in some way when it was invoked from the STA vb app (in a free threaded app, it would be marshalled for the random RPC thread). This means the interface pointer is a temporary one (limted lifetime and scope) than the CreateInstance()/OnFinalConstruct() one. When you CreateThread(), the (worker)thread function itself is not guaranteed to execute with the supplied 'this' while the method scope isnt left. When the method scope is left with "return S_OK", the internal COM/RPC invocations are returning too, possibly destroying any temporary (interface) pointers, freeing memory etc. The case that OnFinalConstruct() works may be an exception, possibly COM-apartment issues. You may compare both 'this' pointers (from OnFinalConstruct() and method invocation). If you *really* need additional threads in your COM server, then follow the threading rules (marshal interface ptrs or synchronize via postmessage to main STA thread or use static instance 'this'). There exist some MSDN articles regarding asynchronous COM and threading. Hope this helps, A. Focht
-
Hiya, at first - Visual Basic only supports Apartment-model even if "free threaded" is preferred in registry. When you create additional threads in your COM app, care must be taken when calling any methods/events from that threads. Without looking into sample code, i would guess the apartment instance pointer, your 'this' must be wrapped/marshalled in some way when it was invoked from the STA vb app (in a free threaded app, it would be marshalled for the random RPC thread). This means the interface pointer is a temporary one (limted lifetime and scope) than the CreateInstance()/OnFinalConstruct() one. When you CreateThread(), the (worker)thread function itself is not guaranteed to execute with the supplied 'this' while the method scope isnt left. When the method scope is left with "return S_OK", the internal COM/RPC invocations are returning too, possibly destroying any temporary (interface) pointers, freeing memory etc. The case that OnFinalConstruct() works may be an exception, possibly COM-apartment issues. You may compare both 'this' pointers (from OnFinalConstruct() and method invocation). If you *really* need additional threads in your COM server, then follow the threading rules (marshal interface ptrs or synchronize via postmessage to main STA thread or use static instance 'this'). There exist some MSDN articles regarding asynchronous COM and threading. Hope this helps, A. Focht
I think you must differntiate between interface pointers and 'this' pointers. If 'this' pointers where to be marshaled it would mean new instances of the objects had to be created. My bet for the original bug posted is that the last instance to the object is released before the thread function is trying to access the supplied this pointer parameter.
-
I have a ATL class with one member function. If i invoke a thread from the member function passing the 'this' pointer as the CreateThread() parameter the data is invalid when the parameter is casted back inside the thread function. A test app demonstrating the problem is available on http://www.codeit.dk/christian/threadtest.zip Like this // This is my member function which // is invoked from within my vb test app STDMETHODIMP Cxx::yy() { DWORD dwID=0; // I put some data into a member variable m_dwFoo = 200873; ::CreateThread(NULL, 0, _TheThread, (LPVOID)this, 0, &dwID); return S_OK; } static DWORD WINAPI _TheThread(LPVOID lpv) { // Cast the lpv pointer back to a class instance // (the this pointer) Cxx* p = (Cxx*)lpv; // Now p->m_dwFoo is corrupted with an invalid value!! return 0; } If I invoke the thread method from within 'OnFinalConstruct()' everything is peachy. It only happens when it is invoked from within a exposed automation method. The class is declared a free-threaded in the registry. Any clues? Christian Skovdal Andersen
I have experienced similar problems due to the type casting back to your class not resulting in the correct vtable. The class I passed had multiple inheritence. In order to fix the problem, I first had to cast the LPVOID to the base class, and then once again cast that resulting pointer into the desired class. Anyhow, that is what worked for me.
-
I think you must differntiate between interface pointers and 'this' pointers. If 'this' pointers where to be marshaled it would mean new instances of the objects had to be created. My bet for the original bug posted is that the last instance to the object is released before the thread function is trying to access the supplied this pointer parameter.
You are absolutely right! I tried to change my vb variable holding the object to a global instance, and it worked like a charm! Apparently Visual Basic dereferences the interface pointer when leaving scope. Thanks for helping me out :-) Christian Skovdal Andersen