Как я могу выйти из потока, когда мой пользовательский интерфейс получает закрытый ввод в MFC - PullRequest
1 голос
/ 09 апреля 2019

Я делаю какую-то программу с 'MFC'.

Когда нажата кнопка, обработчик сообщений создает новый поток для работы.

На работе, пользователь может нажать кнопку B, чтобы выйтиприложение.

В потоке, который создается кнопкой A, используется созданный мной класс C.

Динамический класс выделяет некоторые ресурсы для работы.

КогдаB Кнопка нажата, я хочу отменить выделение ресурсов до того, как мое приложение умрет.

Как я могу это сделать?Помогите, пожалуйста!!!:)

void CMyDlg::On_A_BnClicked() {  // do the job button
    ...
    AfxBeginThread(MyThread, (LPVOID)this);
    ...
}
UINT CMyDlg::MyThread(LPVOID arg) {
    ...
    MyCClass mcc;
    for (int i = 0; i < 100; i++) {
        ...
        mcc.init(file_name);
        mcc.do_somethin();
        mcc.deinit();
        ...
    }
    ...
}
void CMyDlg::On_B_BnClicked() {  // close button
}
void MyCClass::init(file_name) {
    mFileClass.Open(file_name, CFile::modeCreate | CFile::modeWrite);
    // and so on
    ...
}

Если пользователь нажимает кнопку B, когда в MyThread выполняется метод do_somethin.

Как выйти из MyThread после метода deinit () объекта MyCClass?

Я подумал, что нужно создать событие в обработчике кнопок B, а затем отправить сообщение в MyCClass

, чтобы я мог деиницировать все ресурсы в обработчике сообщений MyCClass.

Но, похоже, нетРабота.(

1 Ответ

0 голосов
/ 09 апреля 2019

Общий механизм: Ваш рабочий поток (WT) должен иметь защищенный элемент данных bool bRunning = true (по умолчанию), функцию-член Exit(), которая устанавливает bRunning = false. Цикл WT регулярно проверяет bRunning и прерывает false. Когда вы создаете WT, держите его дескриптор (скажем, hWT), а перед выходом из приложения вызовите hWT->Exit().

-

Если для выхода из WT может потребоваться много времени, добавьте механизм синхронизации. Вид примера:

// WT.h

public:

int Run();

void Exit() // ** Assume that only main-thread call this, once. **
{
    std::mutex m_dummy_mutex;
    std::unique_lock<std::mutex> guard(m_dummy_mutex);

    TRACE("WT state switched to not-running.\n");
    m_bRunning = false; // <-- (1)

    TRACE("Wait for WT stopped notification...\n");
    // (It may happen that the receiver wakes up, although no notification happened.)
    bool rv = m_stopped.wait_for(guard, std::chrono::seconds(5), // <-- (2)
               [this]() {return (m_pResource == nullptr); });
               // 'Spurious Wakeup' mitigation with lambda predicate.

    #ifdef _DEBUG
    if (rv)
        TRACE("WT stopped notification - Recieved.\n");
    else
        TRACE("WT stopped notification - Timeout expired.\n");
    #endif
}

protected:

std::condition_variable m_stopped;
bool                    m_bRunning = true; // Running until Stop().
CResource             * m_pResource = nullptr;

В цикле WT:

// WT.cpp

int CWT::Run()
{
    m_pResource = new CResource; // Let's say CResource is your Resource.

    while (m_bRunning)
    {
        // Do something ... (May take time. Check regularly m_bRunning to abort.)

        if (!m_bRunning)
        {
            delete m_pResource;
            m_pResource = nullptr;
            m_stopped.notify_one(); // <-- (3)
            TRACE("WT stopped. Main-thread notified.\n");
            continue;
        }
    }

    return 0;
}
  • Вместо new / delete лучше использовать смарт-указатели C ++.
...