Question

I examined about stack unwinding on thread procedure in win32 environment.
My test code is the following.

class Dummy
{
public:
    Dummy() { wcout << L"dummy ctor" << endl; }
    ~Dummy() { wcout << L"dummy dtor" << endl; }
};

void InnerFunc()
{
    Dummy dm;

    while(1)
    {
        char *buf = new char[100000000];
    }
}

unsigned WINAPI ThreadFunc(void *arg)
{
    Dummy dm;

    try
    {
        InnerFunc();
    }
        catch(bad_alloc e)
    {
        wcout << e.what() << endl;
    }

    _endthreadex(0);
    return 0;
}

void OuterFunc()
{
    Dummy dm;

    HANDLE hModule;
    hModule = (HANDLE)_beginthreadex(0, 0, ThreadFunc, 0, 0, 0);
    WaitForSingleObject(hModule, INFINITE);
    CloseHandle(hModule);
}

int _tmain(int argc, _TCHAR* argv[])
{
    OuterFunc();
    wcout << e.what() << endl;

    return 0;
}

Output result:
dummy ctor
dummy ctor
dummy ctor
dummy dtor
bad allocation
dummy dtor

As you know, an output of constructor and destructor is not paired. I think that _endthreadex() makes the thread handle be signaled and skips stack unwinding of the thread.

When I tested again without _endthreadex(), I was able to get a result I expected.

In this case, if I need stack unwinding on thread, shouldn't I use _endthreadex() in thread procedure?

Was it helpful?

Solution

I would guess the destructor is never called for the instance created in ThreadFunc. However, you should add a way to distinguish each constructor and destructor call to be sure.

Assuming that's what's happening, it seems pretty clear that endthreadex terminates the thread immediately without cleaning up the stack. The docs explicitly state that endthreadex is called when ThreadFunc returns, so why bother calling it explicitly here?

This is definitely a case where I'd use boost::thread instead. It will do the right thing in terms of thread creation and cleanup without making you worry about the win32-specific details.

OTHER TIPS

Your problem is:

while(1)
{
    char *buf = new char[100000000];
}

You have created a memory leak, on each iteration you create a new object losing any reference to the old object.

Stack Unwinding, clears off all the local objects in that scope,

Dummy dm;

is a object allocated on local storage inside InnerFunc(), Stack Unwinding rightly destroys this object and the single destructor call trace you see is due to this.

Stack Unwinding does not explicitly deallocate the dynamic memory. Each pointer allocated with new[] will have to be explicitly deallocated by calling a delete [] on the same address.

I don't see how it is related to any of the Windows thread functions(I am not much in to windows) but as I already stated you have a problem there.

Solution:
The simple solution to handling cleanups during exceptions is RAII.
You should use a Smart pointer to wrap your raw pointer and then the Smart pointer ensures that your object memory gets appropriately deallocated once the scope ends.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top