#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. Я закодировал с вашим первым советом. Конечно, есть некоторая задержка. Но в качестве альтернативы я создал ожидающий пользовательский интерфейс для пользователя во время ожидания. Спасибо за ваши комментарии. 🙂