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

#c #multithreading #c 11 #stl #mfc

#c #многопоточность #c 11 #stl #mfc

Вопрос:

Я создаю некоторую программу с помощью «MFC».

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

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

В потоке, который создается кнопкой, он использует созданный мной класс 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, когда метод ‘do_somethin’ выполняется в MyThread.

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

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

Чтобы я мог отключить все ресурсы в обработчике сообщений MyCClass.

Но, похоже, это не работает. 🙁

Ответ №1:

Общий механизм: ваш рабочий поток (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;
}
  
  • Вместо создания / удаления лучше использовать смарт-указатели C .

Комментарии:

1. Если я это сделал, мне нужно дождаться окончания do_somethin() метода, который выполняется, когда пользователь нажимает кнопку B (это возможный сценарий, потому do_somethin() что метод требует много времени) ‘0’ Я хочу немедленно выйти из приложения, нажав кнопку закрытия. 🙂

2. @hslee, я добавил «своего рода» решение этой проблемы.

3. Я закодировал с вашим первым советом. Конечно, есть некоторая задержка. Но в качестве альтернативы я создал ожидающий пользовательский интерфейс для пользователя во время ожидания. Спасибо за ваши комментарии. 🙂