I am developing an application with MFC.
The UI thread launch a worker thread and stop it when the app is closing. The issue is that the app is crashing each time it tries to delete the thread.
here is the code :
First the thread class and its implementation :
class FileThread : public CWinThread
{
public:
static FileThread* CreateWorkerThread(LPVOID params, UINT priority, UINT flags);
void InitThread();
void StopThread();
inline HANDLE GetStopHandle() const { return m_stopThread; }
inline HANDLE GetWaitHandle() const { return m_waitThread; }
private:
HANDLE m_stopThread;
HANDLE m_waitThread;
FileThread(): m_stopThread(NULL), m_waitThread(NULL) { }
static UINT MyThreadProc(LPVOID pParam);
};
FileThread* FileThread::CreateWorkerThread(LPVOID params, UINT priority, UINT flags)
{
return (FileThread*) AfxBeginThread(FileThread::MyThreadProc, params, priority, 0, flags);
}
void FileThread::InitThread()
{
m_stopThread = CreateEvent(0, TRUE, FALSE, 0);
m_waitThread = CreateEvent(0, TRUE, FALSE, 0);
}
void FileThread::StopThread()
{
::SetEvent(m_stopThread);
::WaitForSingleObject(m_waitThread, INFINITE);
::CloseHandle(m_stopThread);
::CloseHandle(m_waitThread);
}
UINT FileThread::MyThreadProc(LPVOID pParam)
{
ThreadData* pLink = (ThreadData*)pParam;
BOOL continueProcess = TRUE;
int returnCode = EXITCODE_SUCCESS;
while (continueProcess)
{
if(::WaitForSingleObject(pLink->pMe->GetStopHandle(), 0) == WAIT_OBJECT_0)
{
::SetEvent(pLink->pMe->GetWaitHandle());
continueProcess = FALSE;
}
// the thread is looking for some files...
}
delete pLink; // it was allocated from the UI thread
return returnCode;
}
Then, where I start the thread:
ThreadData * td = new ThreadData();
m_myFileThread = FileThread::CreateWorkerThread((LPVOID)td, THREAD_PRIORITY_LOWEST, CREATE_SUSPENDED);
td->pMe = m_myFileThread;
m_myFileThread->m_bAutoDelete = FALSE;
m_myFileThread->InitThread();
m_myFileThread->ResumeThread();
Finally, the stop (and the crash):
DWORD exitCode;
if (m_myFileThread != NULL && GetExitCodeThread(m_myFileThread->m_hThread, &exitCode) && (exitCode == STILL_ACTIVE))
{
m_myFileThread->StopThread();
if(::WaitForSingleObject(m_myFileThread->m_hThread, 5000) == WAIT_TIMEOUT)
{
TerminateThread(m_myFileThread->m_hThread, EXITCODE_ABORT);
}
}
if (m_myFileThread != NULL)
{
delete m_myFileThread; // => CRASH
}
It seems I try to delete something already deleted and end up with a heap corruption. I have try to set the m_bAutoDelete to TRUE and not delete the thread myself by I got the same crash (while the program was trying to call AfxEndThread).
The thread terminate its thread proc and return the exit code.
It looks to me like there is a problem here:
FileThread* FileThread::CreateWorkerThread(LPVOID params, UINT priority,
UINT flags)
{
return (FileThread*) AfxBeginThread(FileThread::MyThreadProc, params,
priority, 0, flags);
}
AfxBeginThread returns a CWinthread*, so just casting this to a derived class of your own does not make it an instance of that derived class. I'm surprised it works at all.
Rather than deriving FileThread from CWinThread, it might be better to hold a CWinthread* member variable inside your wrapper class and expose the thread handle via an accessor if necessary.
Related
I am running this g_test where I simply initialize and close a client.
TEST(safIpc, createAndCloseClient)
{
std::shared_ptr<fnv::ipcsvc::IpcSvc> safIpc = std::make_shared<fnv::ipcsvc::IpcSvc>();
const std::string& app1 {"/testApp1"};
const std::string& groupName {"wir_clients"};
fnv::ipcsvc::IpcSvcAttrMq attr(fnv::ipcsvc::IpcSvcAttrType::MQ_CLIENT,
app1,
groupName,
"/server");
std::shared_ptr<IpcSvcTestSafHandler> msgHandler = std::make_shared<IpcSvcTestSafHandler>();
// initialize the ipc library
IpcSvcPriv::SharedPtr ipcPrivData {nullptr};
fnv::ipcsvc::IpcSvcRet ret = safIpc->init(attr, msgHandler, ipcPrivData);
EXPECT_EQ(ret, fnv::ipcsvc::IpcSvcRet::SUCCESS);
EXPECT_NE(ipcPrivData, nullptr);
ret = safIpc->close(ipcPrivData, app1); //HANGS here
EXPECT_EQ(fnv::ipcsvc::IpcSvcRet::SUCCESS, ret);
}
In init I create 3 threads: (here is the relevant part of the init code):
1- A process thread
2- a Receive thread
3- A timer thread
int rc = pthread_create(&m_timerThread,
NULL,
&IpcSvcImpl::timer_start,
this);
if (rc != 0)
{
ipcSvcLog(LOGE, "Failed to create timer thread!");
close(tmpPrivData,
attr.getAppId());
return error;
}
pthread_setname_np(m_timerThread,
"IpcSvcTimerThread");
}
// Start the worker threads
int rc = pthread_create(&m_receiveThread,
NULL,
&IpcSvcImpl::receive,
this);
if (rc != 0)
{
//TODO some error log
close(tmpPrivData,
attr.getAppId());
return error;
}
pthread_setname_np(m_receiveThread,
"IpcSvcReceiveThread");
rc = pthread_create(&m_processThread,
NULL,
&IpcSvcImpl::process,
this);
if (rc != 0)
{
//TODO some error log
close(tmpPrivData,
attr.getAppId());
return error;
}
pthread_setname_np(m_processThread,
"IpcSvcProcessThread");
Here is the close function:
IpcSvcRet IpcSvcImpl::close(IpcSvcPriv::SharedPtr privateData,
const std::string& appId)
{
if (!privateData)
{
//TODO log about client not providing sane private data
return IpcSvcRet::FAIL;
}
// acquire the mutex and set close called to true
{
std::lock_guard<std::mutex> guard(m_closeMtx);
m_closed = true;
}
if (m_msgQueue)
{
m_msgQueue->mutexInit();
// writing dummy message to process thread
std::pair<std::array<uint8_t, IPCSVC_MAX_MSG_SIZE>, ssize_t> queueMsg;
m_msgQueue->enqueue(queueMsg);
}
// writing dummy message to receive thread
uint32_t buffer = 0;
sendData(privateData,
(void*)&buffer,
sizeof(uint32_t),
appId);
pthread_join(m_receiveThread,
NULL);
pthread_join(m_processThread,
NULL);
if (m_isClient)
{
m_cv.notify_one();
printf("timer thread hangs\n"); // HANGS HERE ///////////////////////////////////////
pthread_join(m_timerThread,
NULL);
//This line is never reached..
}
delete m_msgQueue;
m_msgQueue = nullptr;
// close the ipc layer
if (m_ipc)
{
m_ipc->close();
delete m_ipc;
m_ipc = nullptr;
}
m_clientsList.clear();
m_hbManager = { };
return IpcSvcRet::SUCCESS;
}
Here is the timer_start function:
The timer thread is a timer that is keeps looping forever unless the fc->m_closed is set to true. It triggers fc->timerExpiry() every 2 seconds.
// timer thread entry
void* IpcSvcImpl::timer_start(void *arg)
{
if (!arg)
{
return nullptr;
}
printf("starting timer\n");
IpcSvcImpl* fc = static_cast<IpcSvcImpl *>(arg);
std::unique_lock<std::mutex> lock(fc->m_closeMtx);
while (!(fc->m_closed))
{
printf("Entering loop\n");
lock.unlock();
auto expireAt = std::chrono::steady_clock::now() +
std::chrono::seconds(fc->getTimerInterval());
fc->timerExpiry();
lock.lock();
printf("here?\n");
fc->m_cv.wait_until(lock, expireAt);
printf("Here 2\n");
}
printf("Exited loop\n\n");
return nullptr;
}
The output of the unittest:
[----------] 5 tests from safIpc
[ RUN ] safIpc.createAndCloseClient
starting timer
Entering loop
closing..
timer thread hangs
pthread join hangs forever, I am not sure why. The "here" prints are never hit, which seems odd.
Thanks for the help!
I'm having trouble understand an exception thrown (read access violation, this is nullptr) when closing my application. The exception occurs on GetDlgItem(IDC_Button1)->EnableWindow(true); when the CDialogEx::OnCancel(); is called. It appears as though the thread is correctly shut down but the error still persists.
When c_DialogFunctionsThreadRunning = false; is called before the MessageBox then the issue does not occur but this also means the thread is terminated before the prompt is accepted or cancelled.
void CFRP_3D_PrinterDlg::OnBnClickedShutdown()
{
if (MessageBox(_T("Close program?"), _T("Program"), MB_ICONQUESTION | MB_OKCANCEL | MB_TOPMOST) == IDOK)
{
c_DialogFunctionsThreadRunning = false;
StateMachine.StateEnter(ShutDown);
CDialogEx::OnCancel();
}
}
void CFRP_3D_PrinterDlg::DialogFunctionsThread()
{
c_DialogFunctionsThreadRunning = true;
CWinThread *CDialogFunctionsThread = AfxBeginThread(DoDialogFunctions, this, THREAD_PRIORITY_NORMAL, 0, 0, nullptr);
CDialogFunctionsThread->m_bAutoDelete = true;
}
UINT CFRP_3D_PrinterDlg::DoDialogFunctions(LPVOID t)
{
CFRP_3D_PrinterDlg *DialogFunctions = static_cast<CFRP_3D_PrinterDlg *>(t);
DialogFunctions->DoDialogFunctions();
return NULL;
}
void CFRP_3D_PrinterDlg::DoDialogFunctions()
{
while (c_DialogFunctionsThreadRunning && c_DialogCreated)
{
GetDlgItem(IDC_Button1)->EnableWindow(true);
Sleep(20);
}
}
This issue is happening because the call CDialogEx::OnCancel() destroy all the UI elements ,then the Thread is trying to access a deleted item, the way to solve this is as follow:
when you create the thread, store the return value in a member variable of the class:
class CFRP_3D_PrinterDlg{
CWinThread *CDialogFunctionsThread;
//.....
};
void CFRP_3D_PrinterDlg::DialogFunctionsThread()
{
c_DialogFunctionsThreadRunning = true;
CDialogFunctionsThread = AfxBeginThread(DoDialogFunctions, this, THREAD_PRIORITY_NORMAL, 0, 0, nullptr);
CDialogFunctionsThread->m_bAutoDelete = true;
}
then in the prompt to cancel it wait for the thread to finish before to call OnCancel, in this example is waiting forever but you use your own time.
void CFRP_3D_PrinterDlg::OnBnClickedShutdown()
{
if (MessageBox(_T("Close program?"), _T("Program"), MB_ICONQUESTION | MB_OKCANCEL | MB_TOPMOST) == IDOK)
{
c_DialogFunctionsThreadRunning = false;
StateMachine.StateEnter(ShutDown);
::WaitForSingleObject(CDialogFunctionsThread->m_hThread, INFINITE);
CDialogEx::OnCancel();
}
}
I've started learing an asynchronous aproach, and
encountered a problem, help me with it.
The purpose is: get from somewhere a char data, and after that do something with it(using as text on the button, in my case). The code, that is pinned below is very slow. The most slowiest moment is a data getting: the fact is that the get(int id) function loads data from internet via WinInet(synchronously), sending the Post methods, and returning the answer.
void some_func()
{
for(int i(0);i<10;i++)
for(int q(0);q<5;q++)
{
char data[100];
strcpy(data, get(i,q)); // i, q - just some identifier data
button[5*i+(q+1)]=new Button(data);
}
}
The first question:
How should it be solved(generaly, I mean, if get has nothing to do with the internet, but runs slow)? I have only one, stupid idea: run get in every separate thread. If it's the right way - how should I do that? Cause, it's wrong to, created 50 threads call from each the get function. 50 get functions?
Second Question
How to realize it with WinInet? Have red MSDN, but it too hardly for me, as for newer, maybe you explain it more simlier?
Thanks
for asynchronous programming you need create some object which will be maintain state - in current case i and q must be not local variables of function but members of object, mandatory reference count to object. and usual file(socket) handle , etc.
function some_func() must have another pattern. it must be member function of object. and it must not call asynchronous get in loop. after call get it must just exit. when asynchronous operation, initiated by get, will be finished - some your callback must be called (if failed initiate asynchronous operation you need yourself just call this callback with error code). in callback you will be have pointer to your object and using it - call some_func(). so some_func() must at begin handle result of previous get call - check for error, handle received data, if no error. than adjust object state (in your case i and q) and if need - call get again. and for initiated all this - need first time call get direct:
begin -> get() -> .. callback .. -> some_func() -> exit
^ ┬
└─────────────────────────────┘
some demo example (with asynchronous read file)
struct SOME_OBJECT
{
LARGE_INTEGER _ByteOffset;
HANDLE _hFile;
LONG _dwRef;
int _i, _q;
SOME_OBJECT()
{
_i = 0, _q = 0;
_dwRef = 1;
_ByteOffset.QuadPart = 0;
_hFile = 0;
}
void beginGet();
void DoSomething(PVOID pvData, DWORD_PTR cbData)
{
DbgPrint("DoSomething<%u,%u>(%x, %p)\n", _i, _q, cbData, pvData);
}
// some_func
void OnComplete(DWORD dwErrorCode, PVOID pvData, DWORD_PTR cbData)
{
if (dwErrorCode == NOERROR)
{
DoSomething(pvData, cbData);
if (++_q == 5)
{
_q = 0;
if (++_i == 10)
{
return ;
}
}
_ByteOffset.QuadPart += cbData;
beginGet();
}
else
{
DbgPrint("OnComplete - error=%u\n", dwErrorCode);
}
}
~SOME_OBJECT()
{
if (_hFile) CloseHandle(_hFile);
}
void AddRef() { InterlockedIncrement(&_dwRef); }
void Release() { if (!InterlockedDecrement(&_dwRef)) delete this; }
ULONG Create(PCWSTR FileName);
};
struct OPERATION_CTX : OVERLAPPED
{
SOME_OBJECT* _pObj;
BYTE _buf[];
OPERATION_CTX(SOME_OBJECT* pObj) : _pObj(pObj)
{
pObj->AddRef();
hEvent = 0;
}
~OPERATION_CTX()
{
_pObj->Release();
}
VOID CALLBACK CompletionRoutine(DWORD dwErrorCode, DWORD_PTR dwNumberOfBytesTransfered)
{
_pObj->OnComplete(dwErrorCode, _buf, dwNumberOfBytesTransfered);
delete this;
}
static VOID CALLBACK _CompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, OVERLAPPED* lpOverlapped)
{
static_cast<OPERATION_CTX*>(lpOverlapped)->CompletionRoutine(RtlNtStatusToDosError(dwErrorCode), dwNumberOfBytesTransfered);
}
void CheckResult(BOOL fOk)
{
if (!fOk)
{
ULONG dwErrorCode = GetLastError();
if (dwErrorCode != ERROR_IO_PENDING)
{
CompletionRoutine(dwErrorCode, 0);
}
}
}
void* operator new(size_t cb, size_t ex)
{
return ::operator new(cb + ex);
}
void operator delete(PVOID pv)
{
::operator delete(pv);
}
};
ULONG SOME_OBJECT::Create(PCWSTR FileName)
{
HANDLE hFile = CreateFile(FileName, FILE_READ_DATA, FILE_SHARE_READ, 0,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
_hFile = hFile;
if (BindIoCompletionCallback(hFile, OPERATION_CTX::_CompletionRoutine, 0))
{
return NOERROR;
}
}
return GetLastError();
}
void SOME_OBJECT::beginGet()
{
const ULONG cbRead = 0x1000;
if (OPERATION_CTX* ctx = new(cbRead) OPERATION_CTX(this))
{
ctx->Offset = _ByteOffset.LowPart;
ctx->OffsetHigh = _ByteOffset.HighPart;
ctx->CheckResult(ReadFile(_hFile, ctx->_buf, cbRead, 0, ctx));
}
}
void ADemo(PCWSTR FileName)
{
if (SOME_OBJECT* pObj = new SOME_OBJECT)
{
if (!pObj->Create(FileName))
{
pObj->beginGet();
}
pObj->Release();
}
}
I want to make a shop and an inventory in my game but my code keeps crashing. My program crash at addToInventory->addInventoryItems(name); and I am not sure why.
// inventory.h
struct InventoryItems
{
string type;
};
vector<InventoryItems*> inventoryItems;
// inventory.cpp
void Inventory::addInventoryItems(string itemName)
{
addItem->type = itemName;
inventoryItems.push_back(addItem);
}
// shop.h
Inventory* addToInventory;
// shop.cpp
void Shop::purchase()
{
string name = touchableSprites[i]->getSprite()->getName();
addToInventory->addInventoryItems(name); //crashes here
}
Thanks alot!
I guess problem in addItem, because you didn't set type
void Inventory::addInventoryItems(string itemName)
{
InventoryItems addItem;
addItem->type = itemName;
inventoryItems.push_back(addItem);
}
Such errors usually occur when the execution of the function is performed at the same time.
For example : )
#define SET_DEFAULT_DELAY {Sleep(100)}
InventoryItems* addToInventory;
TCHAR g_tszParam[MAX_PATH];
DWORD WINAPI _VECTOR_OPERATION_01(LPVOID lParam)
{
while(TRUE)
{
if(0 == _tcsicmp(g_tszParam, _T("Default_Value"))
{
addToInventory->addInventoryItems(g_tszparam);
}
SET_DEFAULT_DELAY;
}
}
DWORD WINAPI _VECTOR_OPERATION_02(LPVOID lParam)
{
while(TRUE)
{
if(0 == _tcsicmp(g_tszParam, _T("Special_Value"))
{
addToInventory->addInventoryItems(g_tszparam);
}
SET_DEFAULT_DELAY;
}
}
int _tmain()
{
...
HANDLE hThread[2];
hThread[0] = CreateThread(NULL, 0, _VECTOR_OPERATION_01, NULL, 0, 0);
if(INVALID_HANDLE_VALUE != hThread[0])
{
CloseHandle(hThread[0]);
}
hThread[1] = CreateThread(NULL, 0, _VECTOR_OPERATION_02, NULL, 0, 0);
if(INVALID_HANDLE_VALUE != hThread[1])
{
CloseHandle(hThread[1]);
}
...
return 1;
}
In this case, the result of thread execution depends on g_tszParam values. However, if one thread executes a Vector-related function while another executes a Vector-related function in another thread, a conflict occurs.
I don't know what the speculator is because I don't have your source code.
But it seems to me this is the case why that error occured.
I'm developing an ActiveX video player. It is in-process component in a DLL. I'm using Visual Studio 2010.
I need it to have a separate thread, which would start once, when the component is loaded, create Direct3D9 object and Direct3D9 device, then stop on the component unloading and destroy these objects. While the component is running I'd like this thread to periodically call TestCooperativeLevel and reset D3D device if needed.
I'm doing this since the client application can create several instances of my player, but it is strongly recommended to have only one instance of D3D9 object and device.
I've declared a class with static methods and members, whose constructor calls _beginthreadex() and starts the thread.
Here are the code excerpts (WITH ERRORS).
// .h
class D3DManager {
static mutex d3; // mutex is my own class, just a wrapper around CriticalSection
static LPDIRECT3D9 g_d3d;
static LPDIRECT3DDEVICE9 g_d3ddev;
static D3DPRESENT_PARAMETERS g_d3dpp;
static int g_d3d_counter;
static HANDLE hthread;
static HANDLE exitev;
static bool exit_flag;
static mutex exit_mutex;
public:
D3DManager();
~D3DManager();
static unsigned int __stdcall thread(void *);
static void stop(void) {
exit_mutex.lock();
exit_flag = true;
SetEvent(exitev);
exit_mutex.unlock(); }
static bool exit_signal(void) {
exit_mutex.lock();
bool result = exit_flag;
exit_mutex.unlock();
return exit_flag; }
static void CreateD3DDevice(LPDIRECT3D9& d3dobj, LPDIRECT3DDEVICE9& d3ddev);
static void DestroyD3DDevice(void);
static void GetSwapChain(HWND hwnd, LPDIRECT3DSWAPCHAIN9& chain);
static void release_d3d(void);
static void LockDevice(void) { d3.lock(); };
static void UnlockDevice(void) { d3.unlock(); };
};
//.cpp
mutex D3DManager::d3;
LPDIRECT3D9 D3DManager::g_d3d = NULL;
LPDIRECT3DDEVICE9 D3DManager::g_d3ddev = NULL;
D3DPRESENT_PARAMETERS D3DManager::g_d3dpp;
int D3DManager::g_d3d_counter = 0;
HANDLE D3DManager::hthread;
HANDLE D3DManager::exitev;
bool D3DManager::exit_flag = false;
mutex D3DManager::exit_mutex;
// this variable will be single and shared by all activeX instances
static D3DManager d3dm;
D3DManager::D3DManager()
{
exitev = CreateEvent(NULL, true, false, NULL);
hthread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL);
_OutputDebugString("D3DManager: thread created handle %x\n", hthread); // my wrapper around OutputDebugString
}
D3DManager::~D3DManager()
{
stop();
HRESULT hr = WaitForSingleObject(hthread, 1000);
if (hr == WAIT_ABANDONED) {
TerminateThread(hthread, 0);
release_d3d();
}
CloseHandle(exitev);
}
unsigned int __stdcall D3DManager::thread(void *)
{
create_d3d9();
while(!exit_signal()) {
WaitForSignleObject(exitev, 500);
d3.lock();
HRESULT hr = g_d3ddev->TestCooperativeLevel();
switch(hr) {
case S_OK:
break;
case D3DERR_DEVICENOTRESET :
// Fill DISPLAYPARAMETERS
g_d3ddev->Reset();
break;
default:
break;
}
d3.unlock();
}
///////// This text is never seen
OutputDebugString("D3dManagert exit from while loop\n");
////////
release_d3d();
_endthreadex(0);
return 0;
}
My component is embedded in the WindowsForms form, writtent in C#.
The problem is when I close the form, the thread is terminated inside while loop and never gets to the code after it. I've never seen the text from OutputDebugString, the release_d3d() is also never called, and I see a lot of messages from d3d debug about memory leak. If I set a breakpoint, it is never hit.
All I see is the message:
The thread 'Win32 Thread' (0x1044) has exited with code 0 (0x0)
When I set up a breakpoint in the destructor, I get it hit, but after the messages about video memory leaks.
I've also enabled debug break on C++ Exceptions and Win32 Exception in the Studio, but none were triggered.
Update.
Have read in the MSDN that all threads are terminated, when any of them calls exit, _exit, or abort or ExitProcess and tried stting in the constructor atexit handler:
D3DManager::D3DManager()
{
exitev = CreateEvent(NULL, true, false, NULL);
hthread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL);
_OutputDebugString("D3DManager: thread created handle %x\n", hthread);
atexit(&release_d3d);
}
Still no luck. release_d3d is called after I've got messages about video memory leak. Moreover I've got exception fault.
Update 2.
Here is the edited code
// .h
class D3DManager {
static mutex d3; // mutex is my own class, just a wrapper around CriticalSection
static LPDIRECT3D9 g_d3d;
static LPDIRECT3DDEVICE9 g_d3ddev;
static D3DPRESENT_PARAMETERS g_d3dpp;
static int g_d3d_counter;
static HANDLE hthread;
static HANDLE exitev;
public:
D3DManager();
~D3DManager();
static unsigned int __stdcall thread(void *);
static void stop(void) { SetEvent(exitev); }
static void CreateD3DDevice(LPDIRECT3D9& d3dobj, LPDIRECT3DDEVICE9& d3ddev);
static void DestroyD3DDevice(void);
static void GetSwapChain(HWND hwnd, LPDIRECT3DSWAPCHAIN9& chain);
static void release_d3d(void);
static void LockDevice(void) { d3.lock(); };
static void UnlockDevice(void) { d3.unlock(); };
};
//.cpp
mutex D3DManager::d3;
LPDIRECT3D9 D3DManager::g_d3d = NULL;
LPDIRECT3DDEVICE9 D3DManager::g_d3ddev = NULL;
D3DPRESENT_PARAMETERS D3DManager::g_d3dpp;
int D3DManager::g_d3d_counter = 0;
HANDLE D3DManager::hthread;
HANDLE D3DManager::exitev;
// this variable will be single and shared by all activeX instances
static D3DManager d3dm;
D3DManager::D3DManager()
{
exitev = CreateEvent(NULL, true, false, NULL);
hthread = (HANDLE)_beginthreadex(NULL, 0, thread, NULL, 0, NULL);
_OutputDebugString("D3DManager: thread created handle %x\n", hthread); // my wrapper around OutputDebugString
}
D3DManager::~D3DManager()
{
stop();
HRESULT hr = WaitForSingleObject(hthread, 1000);
if (hr == WAIT_TIMEOUT) {
TerminateThread(hthread, 0);
release_d3d();
}
CloseHandle(exitev);
}
unsigned int __stdcall D3DManager::thread(void *)
{
create_d3d9();
while(WAIT_TIMEOUT == WaitForSingleObject(exitev, 500)) {
d3.lock();
HRESULT hr = g_d3ddev->TestCooperativeLevel();
switch(hr) {
case S_OK:
break;
case D3DERR_DEVICENOTRESET :
// Fill DISPLAYPARAMETERS
g_d3ddev->Reset();
break;
default:
break;
}
d3.unlock();
}
///////// This text is never seen
OutputDebugString("D3dManagert exit from while loop\n");
////////
release_d3d();
_endthreadex(0);
return 0;
}
Why wait on the stop object and then, if signaled, still perform the body of the code? Try
while(WAIT_TIMEOUT==WaitForSingleObject(exitev, 500){
..
}
also, I'm not sure what all that !exit_signal() and exit_mutex is for? Why do you need a mutex, or, for that matter, an exit boolean when you already have an event to signal? Is there some more code that signals the event for some other reason than stopping? I notice that you have typo'd the WFSO - 'WaitForSignleObject', so you have not posted your real code.
Not sue about 'if (hr == WAIT_ABANDONED)' either. I hardly ever wait for threads to terminate and so I don't know for sure if/why that return is made when waiting on a thread handle.
I see that your exit_signal() copies the value but does not return it. There can be chances that the variable exit_flag is changed after you get out of the synchronized block of code and your exit_signal() returns false.