From: Jack on
Dear all,

First some code snippets,
//////////////////////////////////////////////////////////////////////////
class Thread
{
public:
Thread(std::auto_ptr<Runnable> runnable_);
Thread();
virtual ~Thread();
void start();
void *join();

private:
HANDLE hThread;
unsigned winThreadID;
std::auto_ptr<Runnable> runnable;
Thread(const Thread&);
const Thread& operator = (const Thread&);
void setCompleted();
void *result;
virtual void *run() { return 0; }
static unsigned WINAPI startThreadRunnable(LPVOID pVoid);
static unsigned WINAPI startThread(LPVOID pVoid);
void PrintError(LPTSTR lpszFunction, LPSTR fileName, int lineNumber);
};

Thread::Thread(std::auto_ptr<Runnable> runnable_) : runnable(runnable_)
{
if (runnable.get() == NULL)
PrintError("Thread(std::auto_ptr<Runnable> runnable_) failed at ",
__FILE__, __LINE__);
hThread = (HANDLE) _beginthreadex(NULL, 0, Thread::startThreadRunnable,
(LPVOID) this, CREATE_SUSPENDED, &winThreadID);
if (!hThread)
PrintError("_beginthreadex failed at ", __FILE__, __LINE__);
}

Thread::Thread() : runnable(NULL)
{
hThread = (HANDLE) _beginthreadex(NULL, 0, Thread::startThread,
(LPVOID)this, CREATE_SUSPENDED, &winThreadID);
if (!hThread)
PrintError("_beginthreadex failed at ", __FILE__, __LINE__);
}


unsigned WINAPI Thread::startThreadRunnable(LPVOID pVoid)
{
Thread *runnableThread = static_cast<Thread *>(pVoid);
runnableThread->setCompleted();
return reinterpret_cast<unsigned>(runnableThread->result);
}

//// Destructor called before this function is.
//// so the whole context gets destroyed
//// but why did that happen?
unsigned WINAPI Thread::startThread(LPVOID pVoid)
{
Thread *aThread = static_cast<Thread *>(pVoid);
aThread->result = aThread->run();
aThread->setCompleted();
return reinterpret_cast<unsigned>(aThread->result);
}

Thread::~Thread()
{
if (winThreadID != GetCurrentThreadId())
{
DWORD rc = CloseHandle(hThread);
if (!rc)
PrintError ("CloseHandle failed at ", __FILE__, __LINE__);
}
}

void Thread::start()
{
assert(hThread != NULL);
DWORD rc = ResumeThread(hThread);
if (!rc)
PrintError("ResumeThread failed at ", __FILE__, __LINE__);
}

void *Thread::join()
{
return result;
}

void Thread::setCompleted()
{
}
/////////////////////////////////////////////////////////////////////////////////////////

class BFThread : public Thread
{
public:
BFThread(int ID) : myID(ID) { }
virtual void *run()
{
return reinterpret_cast<void *>(myID);


}
private:


int myID;
};

//////////////////////////////////////////////////////////////////////////////////

// main module
std::auto_ptr<BFThread> thread1(new BFThread(1));

thread1->start();

int result1 = reinterpret_cast<int>(thread1->join());

///////////////////////////////////////////////////////////////////////////////

The errors are:
First-chance exception at 0x004177c7 in GridPartition.exe: 0xC0000005:
Access violation reading location 0xfeeefef2.
Unhandled exception at 0x004177c7 in GridPartition.exe: 0xC0000005: Access
violation reading location 0xfeeefef2.


I wrote the comments above. Could anyone please check my code why the
destructor is called before the startThread function is?
Thanks
Jack



From: Ulrich Eckhardt on
Jack wrote:
> void *Thread::join()
> {
> return result;
> }

This is missing a WaitForSingleObject() call to wait for the thread to
terminate.

Another comment: Take a look at Boost.Thread, which uses a slightly
different design. There, you don't derive from a thread class in order to
add your code to run in that thread. Similar to a file, its thread class is
just a means to communicate with a thread, but the lifetime of the thread
itself is independent thereof.

Also, it doesn't require any code to derive from a "Runnable" baseclass
either, it only requires the passed argument to be callable (e.g. a
function pointer or a class with overloaded operator()) and copyable (so it
can be given to the thread to start).

Lastly, if e.g. a passed pointer is incorrectly zero, I would either assert
or throw an exception. Just printing an error (PrintError) and continuing
isn't going to help.

Uli

--
C++ FAQ: http://parashift.com/c++-faq-lite

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932
From: Jack on
Thanks Ulrich for sheding lights on this!!!
Jack


From: Alexander Grigoriev on
Are you by any chance using Thread object on the stack?

"Jack" <jl(a)knight.com> wrote in message
news:Okgq%23Px1KHA.140(a)TK2MSFTNGP05.phx.gbl...
> Dear all,
>
> First some code snippets,
> //////////////////////////////////////////////////////////////////////////
> class Thread
> {
> public:
> Thread(std::auto_ptr<Runnable> runnable_);
> Thread();
> virtual ~Thread();
> void start();
> void *join();
>
> private:
> HANDLE hThread;
> unsigned winThreadID;
> std::auto_ptr<Runnable> runnable;
> Thread(const Thread&);
> const Thread& operator = (const Thread&);
> void setCompleted();
> void *result;
> virtual void *run() { return 0; }
> static unsigned WINAPI startThreadRunnable(LPVOID pVoid);
> static unsigned WINAPI startThread(LPVOID pVoid);
> void PrintError(LPTSTR lpszFunction, LPSTR fileName, int lineNumber);
> };
>
> Thread::Thread(std::auto_ptr<Runnable> runnable_) : runnable(runnable_)
> {
> if (runnable.get() == NULL)
> PrintError("Thread(std::auto_ptr<Runnable> runnable_) failed at ",
> __FILE__, __LINE__);
> hThread = (HANDLE) _beginthreadex(NULL, 0, Thread::startThreadRunnable,
> (LPVOID) this, CREATE_SUSPENDED, &winThreadID);
> if (!hThread)
> PrintError("_beginthreadex failed at ", __FILE__, __LINE__);
> }
>
> Thread::Thread() : runnable(NULL)
> {
> hThread = (HANDLE) _beginthreadex(NULL, 0, Thread::startThread,
> (LPVOID)this, CREATE_SUSPENDED, &winThreadID);
> if (!hThread)
> PrintError("_beginthreadex failed at ", __FILE__, __LINE__);
> }
>
>
> unsigned WINAPI Thread::startThreadRunnable(LPVOID pVoid)
> {
> Thread *runnableThread = static_cast<Thread *>(pVoid);
> runnableThread->setCompleted();
> return reinterpret_cast<unsigned>(runnableThread->result);
> }
>
> //// Destructor called before this function is.
> //// so the whole context gets destroyed
> //// but why did that happen?
> unsigned WINAPI Thread::startThread(LPVOID pVoid)
> {
> Thread *aThread = static_cast<Thread *>(pVoid);
> aThread->result = aThread->run();
> aThread->setCompleted();
> return reinterpret_cast<unsigned>(aThread->result);
> }
>
> Thread::~Thread()
> {
> if (winThreadID != GetCurrentThreadId())
> {
> DWORD rc = CloseHandle(hThread);
> if (!rc)
> PrintError ("CloseHandle failed at ", __FILE__, __LINE__);
> }
> }
>
> void Thread::start()
> {
> assert(hThread != NULL);
> DWORD rc = ResumeThread(hThread);
> if (!rc)
> PrintError("ResumeThread failed at ", __FILE__, __LINE__);
> }
>
> void *Thread::join()
> {
> return result;
> }
>
> void Thread::setCompleted()
> {
> }
> /////////////////////////////////////////////////////////////////////////////////////////
>
> class BFThread : public Thread
> {
> public:
> BFThread(int ID) : myID(ID) { }
> virtual void *run()
> {
> return reinterpret_cast<void *>(myID);
>
>
> }
> private:
>
>
> int myID;
> };
>
> //////////////////////////////////////////////////////////////////////////////////
>
> // main module
> std::auto_ptr<BFThread> thread1(new BFThread(1));
>
> thread1->start();
>
> int result1 = reinterpret_cast<int>(thread1->join());
>
> ///////////////////////////////////////////////////////////////////////////////
>
> The errors are:
> First-chance exception at 0x004177c7 in GridPartition.exe: 0xC0000005:
> Access violation reading location 0xfeeefef2.
> Unhandled exception at 0x004177c7 in GridPartition.exe: 0xC0000005: Access
> violation reading location 0xfeeefef2.
>
>
> I wrote the comments above. Could anyone please check my code why the
> destructor is called before the startThread function is?
> Thanks
> Jack
>
>
>


From: Jack on
Hi Alex,

> Are you by any chance using Thread object on the stack?

Ummm.... I set out the thread as a local variable of the method, I vaguely
remember one of you said that although the var is on the stack, the thread
itself should be on the heap... no? correct me if I am wrong...
Thanks
Jack