Сбой при удалении темы

Я разрабатываю приложение с MFC. Поток пользовательского интерфейса запускает рабочий поток и останавливает его, когда приложение закрывается. Проблема в том, что приложение вылетает каждый раз, когда пытается удалить поток.

вот код:

Сначала класс потока и его реализация:

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;
}

Затем, где я начинаю поток:

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();

Наконец, остановка (и крах):

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
}

Кажется, я пытаюсь удалить что-то уже удаленное и получаю повреждение кучи. Я попытался установить для m_bAutoDelete значение TRUE и не удалять поток самостоятельно, у меня такой же сбой (пока программа пыталась вызвать AfxEndThread).

Поток завершает свою процедуру потока и возвращает код выхода.


person Jonyjack    schedule 20.01.2014    source источник


Ответы (1)


Мне кажется, что здесь есть проблема:

FileThread* FileThread::CreateWorkerThread(LPVOID params, UINT priority, 
                                           UINT flags)
{
    return (FileThread*) AfxBeginThread(FileThread::MyThreadProc, params, 
                                        priority, 0,  flags);
}

AfxBeginThread возвращает CWinthread*, поэтому простое приведение этого к вашему собственному производному классу не делает его экземпляром этого производного класса. Я удивлен, что это вообще работает.

Вместо того, чтобы выводить FileThread из CWinThread, может быть лучше хранить переменную-член CWinthread* внутри вашего класса-оболочки и при необходимости предоставлять дескриптор потока через метод доступа.

person Roger Rowland    schedule 20.01.2014
comment
В следующем примере MSDN показано, как правильно выполнить преобразование msdn.microsoft.com/en -us/library/z2h4xz23.aspx Также CWinthread имеет механизм автоматического удаления: msdn.microsoft.com/en-us/library/4bbe9bte.aspx - person odedsh; 20.01.2014
comment
@odedsh Ну, вроде как, это создает поток пользовательского интерфейса, который имеет насос сообщений (необходим для сокетов) - его может использовать как рабочий поток, но во многих ситуациях это, возможно, немного излишне. - person Roger Rowland; 20.01.2014
comment
@Roger Rowland: Это та проблема, о которой ты думаешь, КОНЕЧНО, ЧЕЛОВЕК! Я НАСТОЛЬКО ГЛУПАЯ?! ;) Большое спасибо, я завернул CWinThread в свой класс, и все в порядке. Задача решена - person Jonyjack; 20.01.2014