A3. Самый оптимальный по-моему способ: Это запустить worker thread – второй поток (если пока только один :)) ) апликации. В качестве параметра передать туда структуру с необходимыми данными, а можно и ничего не передавать. Если все данные хранятся в наследнике CWinApp (дальше – CMyApp) , то получить доступ к объекту апликации можно с помощью функции AfxGetApp. Единственное замечание по передаче данных из одного потока в другой заключается в том, что надо доступаться ТОЛЬКО к мемберам класса – нельзя вызывать функции класса из другого потока (вернее, можно, если они не изменяют данных класса или не обращаются к оконным функциям класса (относиться к наследникам CWnd)). В итоге имеем схему:
1. Создается worker thread (поток одной функции, при ее завершении завершается и поток). В качестве параметра функции AfxBeginThread передается указатель на необходимые данные.
2. В основном потоке создается собственное сообщение, сигнализирующее о завершении потока. Оно будет брошено рабочим потоком перед своим завершением с помощью PostMessage (при работе с потоками я предпочитаю PostMessage для обмена такого рода сообщениями, ведь SendMessage ждет завершения работы обработчика события, что часто просто не нужно).
3. Запущенный поток выполняет всю черновую работу, в то время как основной поток апликации занимается важными делами, а именно – ничего не делает, знай крутит себе цикл обработки сообщений и не жужжит.
4. По завершении работы, worker thread посылает основному потоку мессагу, мол я закончил, выкладывает результаты так, чтобы основной знал где они (как это сделать – миллионы способов :)), в частности, передать в завершающем сообщении указатель на данные результата. )
Примерный код таков.
UINT WorkerThreadFunction(WPARAM, LPARAM lpData) {
// тутачки работаем с lpData и выполняем
// всю необходимую работу
// результат запихиваем в память,
// а адрес на нее – в lpResult
AfxGetMainWnd->PostMessage(IID_WORKER_THREAD_END, 0, lpResult);
// возвращаем код успеха (а вообще это на ваш вкус)
return 0;
}
void CMyApp::OnStartExecution {
// заполняем lpData нужными данными, и вызываем ..
CWinThread *pThread = AfxBeginThread(WorkerThreadFunction, lpData);
if (!pThread) {
// Не смогли запустить поток.
// Правда обычно этот код не выполняется :)).
// Я до сих пор не знаю ситуации, когда поток
// может не запуститься, кроме low memory.
AfxMessageBox(_T("Can't start thread."));
}
}
LRESULT CMyApp::OnWorkerThreadEnd(WPARAM wParam, LPARAM lpResult) {
// тутачки обрабатываем завершение расчетов.
}
Замечания:
1. Объявлять обработчик сообщения ID_WORKER_THREAD_END надо через ON_MESSAGE макрос
2. Потоков запускать можно сколько душе угодно (если хватает памяти :)) ).
3. Повторюсь: важно понимать, что доступ к данным может быть одновременным из разных потоков. Поэтому необходима синхронизация. чтобы не получилось ситуации, что один поток пишет, а второй читает в одно время – как результат, можно разрушить логическую целостность данных. Поэтому в приведенных примерах лучше сбрасывать данные в отдельный блок памяти и передавать указатель на него. И функция рабочего потока, и обработчик сообщения завершения должны освобождать передаваемую им память.