3

In the constructor of one of my classes I call the Windows function CreateThread as last operation. The thread is created to execute immediately and I pass the this pointer of my class as lpParameter.

In the thread procedure I cast the parameter passed back to a pointer of my class and name it pThis.

I can see that pThis points to the same memory location as the this pointer I passed when I called CreateThread. However if I look at the member variables accessed by pThis->... they all have wrong values.

I expected the value of this->member_variable used in the class to which the this pointer belongs to be the same as the one I get when writing pThis->member_variable in the thread's procedure.

If I call CreateThread in another member function (not the constructor) everything behaves correctly.

Hence the question: Is it forbidden to call the Windows function CreateThread from within the constructor of a C++ class? If yes, what is the problem?

Clarification:

1) I can confirm that the object always exists. The object gets out of scope only when the entire program ends. As I already said: calling CreateThread from some other member function does work.

2) Corrected the 'wired' typo, should have been 'weird', sorry.

Some code:

I try to post code snippets reducing things to the bare minimum while maintaining the 'faulty' parts.

class CTimerW32 : public CTimer
{
    public:
        CTimerW32();
        ~CTimerW32();

    private:
        static void CALLBACK TimerCallback(LPVOID lpParam, BOOLEAN bReason);
        static DWORD WINAPI WaitCompletition(LPVOID lpParam);

    private:
        HANDLE m_hCompletitionEvent;
        HANDLE m_hCompletitionThread;
        bool m_bStartDeferred;
};

You can safely ignore the baseclass CTimer as it is just an abstract baseclass enabling build on different platforms.

CTimerW32::CTimerW32()
{
    m_bStartDeferred= false;
    m_hCompletitionEvent= CreateEvent(NULL, FALSE, FALSE, NULL);
    m_hCompletitionThread= CreateThread(NULL, 0, WaitCompletition, this, 0, NULL);
}

Here I can see that m_hCompletitionEvent is valid after the call to CreateEvent.

DWORD WINAPI CTimerW32::WaitCompletition(LPVOID lpParam)
{
    CTimerW32* pThis;
    DWORD dwRet;

    pThis= (CTimerW32*)(lpParam);

    while (true) {
        // just wait for the completition event to be signaled
        dwRet= WaitForSingleObject(pThis->m_hCompletitionEvent, INFINITE);

        // ...
        if (pThis->m_bStartDeferred) {
            // ...
        }
    }

Here things are going wrong in the call to WaitForSingleObject. As already stated the this pointer of the object of class CTimerW32 (now pThis) still has the same value as the this pointer during thread creation. However the handle in pThis->m_hCompletitionEvent seems to be random data. It is not the value observed after the call to CreateEvent in the constructor.

felix
  • 61
  • 7
  • Does the object still exist by the time the thread runs? It's not been destructed in the original thread by then? – jcoder Jul 25 '12 at 16:32
  • 1
    Can you post some code: the declaration of `pThis`, your call to `CreateThread`, and where you cast `pThis` to your class type? And what does "weird" mean? What values are you expecting, and what are you seeing? – tenfour Jul 25 '12 at 16:45
  • Are You shure that object exists all the time when thread is working? – Jacek Jul 25 '12 at 16:34

2 Answers2

2

Creating a thread in a constructor should not be an issue. Also, your object should be fully initialized by the initializer list before any code in the constructor is run to create the thread, so initialization probably isn't an issue.

It is likely that the object you're watching is out of scope and its destructor is called prior to you observing it in the new thread. Try creating the object dynamically with new and see if this still happens, I bet it doesn't as the object won't get destroyed when it falls out of scope.

Obviously, you should keep a pointer to this object in a higher scope so you can eventually delete it too :)

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
0

You will probably have the best luck debugging this problem with the aid of Application Verifier. If you turn on the "Basics" option for your program, it will enable PageHeap, which will fault immediately when memory gets freed. If you're stack-allocating the timer variable, you're in less luck, but it should be possible to see in the debugger if at the time you notice the corruption, the thread which created the timer is still within the function where the CTimerW32 function was declared.

Lastly, for this usecase, the Threadpool Timer APIs may work more easily, and with less resource consumption, than creating your own dedicated thread.

Neeraj Singh
  • 589
  • 3
  • 6