Работа с потоками (threads) в MFC
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 20.12.16 12:08
Оценка:
Не подскажете ли, уважаемые коллеги, как лучше всего работать с потоками (threads) в MFC?

Есть функция, производящая математические вычисления. Эта функция большая по длине и её действия происходят в цикле до выполнения некоего условия. Эта функция работает в консольном режиме--ввод и вывод данных там происходит с помощью консольного окна.
Как лучше поместить эту функцию в поток--использовать класс CWinThread, воспользоваться функцией AfxBeginThread или же использовать функции WinAPI для работы с потоками?
1613 г. = 2024 г.
Re: Работа с потоками (threads) в MFC
От: _Butch_  
Дата: 20.12.16 12:41
Оценка:
std::thread
Re[2]: Работа с потоками (threads) в MFC
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 20.12.16 13:13
Оценка:
Здравствуйте, _Butch_, Вы писали:

_B_>std::thread


А если функция, которую я хочу поместить в поток, является членом класса--то как быть?
1613 г. = 2024 г.
Re[3]: Работа с потоками (threads) в MFC
От: _Butch_  
Дата: 20.12.16 13:48
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>Здравствуйте, _Butch_, Вы писали:


_B_>>std::thread


RF>А если функция, которую я хочу поместить в поток, является членом класса--то как быть?



#include <iostream>
#include <chrono>
#include <thread>

class Dumb
{
private:
    int id;

public:
    Dumb(int _id)
        : id(_id)
    {

    }

    void stupid()
    {
        for (int i = 0; i < 10; i++)
        {
            using namespace std::chrono_literals;
            std::cout << id << " is thinking..." << std::endl;
            std::this_thread::sleep_for(1s);
        }
    }
};

int main()
{
    Dumb d1(1);
    std::thread t1(&Dumb::stupid, &d1);

    Dumb d2(2);
    std::thread t2(&Dumb::stupid, &d2);

    t1.join();
    t2.join();

    return 0;
}
Re: Работа с классом CWinThread
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 20.12.16 14:29
Оценка:
Ещё у меня такой вопрос--как работать с классом CWinThread?
Как привязать некую функцию к потоку CWinThread? (Меня интересует как обычная функция, так и функция-член класса).
Надо ли создавать класс-потомок от CWinThread для того, чтобы в нём выполнялась некая функция, или же достаточно самого класса CWinThread?
Если же нужно создавать класс-потомок от CWinThread, то какие методы там следует переопределять?
И как уничтожить поток? (Для создания потока используется функция CWinThread::Create, для запуска--функция CWinThread::SuspendThread, для продолжения работы потока--функция CWinThread::ResumeThread, а как принудительно уничтожить поток, не дожидаясь завершения его выполнения?)
1613 г. = 2024 г.
Re[2]: Работа с классом CWinThread
От: Evgeniy Skvortsov Россия  
Дата: 20.12.16 15:14
Оценка: +1
Здравствуйте, RussianFellow, Вы писали:

RF>Ещё у меня такой вопрос--как работать с классом CWinThread?


Не заморачивайся с CWinThread — для рабочих потоков оно того не стоит.
AfxBeginThread, CreateThread, std::thread — на выбор

Вкратце почему не нужен CWinThread — там внутри создаётся поток и крутится цикл сообщений, как у основного потока приложения. Переопределять нужно виртуальную функцию Run. Но что бы поток завершился, просто выйти из этой функции недостаточно. Поток будет жить, пока не получит сообщение WM_QUIT, далее он автоматически самоубьется и грохнет все свои данные. Если есть какие-то переменные члены которые нужны после завершения работы, надо перед созданием ставить переменную bAutoDelete = FALSE и руками освобождать память.

В общем для простого потока "что-то посчитать в фоне" слишком много ненужных танцев с бубном.
Re[3]: Работа с классом CWinThread
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 21.12.16 06:12
Оценка:
Здравствуйте, Evgeniy Skvortsov, Вы писали:

ES>Здравствуйте, RussianFellow, Вы писали:


RF>>Ещё у меня такой вопрос--как работать с классом CWinThread?


ES>Не заморачивайся с CWinThread — для рабочих потоков оно того не стоит.

ES>AfxBeginThread, CreateThread, std::thread — на выбор

Хорошо, а как тогда при использовании AfxBeginThread или CreateThread приостановить поток, потом запустить его на продолжение, как уничтожить поток?
Не могли бы Вы привести примеры (простейшие), как использовать AfxBeginThread и CreateThread или дать ссылку на эти примеры?
1613 г. = 2024 г.
Re[4]: Работа с классом CWinThread
От: aloch Россия  
Дата: 21.12.16 07:39
Оценка: 6 (1) +2
Здравствуйте, RussianFellow, Вы писали:


RF>Не могли бы Вы привести примеры (простейшие), как использовать AfxBeginThread и CreateThread или дать ссылку на эти примеры?


Рихтера про потоки почитайте, прежде чем во все это влезать.


Re[4]: Работа с классом CWinThread
От: Evgeniy Skvortsov Россия  
Дата: 21.12.16 07:55
Оценка: 2 (1)
Здравствуйте, RussianFellow, Вы писали:

RF> Хорошо, а как тогда при использовании AfxBeginThread или CreateThread приостановить поток, потом запустить его на продолжение,

Можно создать поток изначально остановленным установив флаг dwCreationFlags в CREATE_SUSPENDED
Продолжить выполнение — ResumeThread
Приостановить — SuspendThread

RF> как уничтожить поток?

Штатное завершение — просто выйти из функции потока.
Аварийное — TerminateThread

Желательно вызвать CloseHandle после окончания работы потока

Подробная информация

RF> Не могли бы Вы привести примеры (простейшие), как использовать AfxBeginThread и CreateThread или дать ссылку на эти примеры?


Как обычно
Re[5]: Работа с классом CWinThread
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 21.12.16 08:18
Оценка:
Здравствуйте, aloch, Вы писали:

A>Здравствуйте, RussianFellow, Вы писали:



RF>>Не могли бы Вы привести примеры (простейшие), как использовать AfxBeginThread и CreateThread или дать ссылку на эти примеры?


A>Рихтера про потоки почитайте, прежде чем во все это влезать.


Как книга называется?
1613 г. = 2024 г.
Re[6]: Работа с классом CWinThread
От: Evgeniy Skvortsov Россия  
Дата: 21.12.16 08:41
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>Как книга называется?


Дж. Рихтер. Windows для профессионалов. Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows. Изд-ва: Питер, Русская Редакция, 2001 г., 752 стр. ISBN 5-272-00384-5, 1-57231-996-8
Re[5]: Работа с классом CWinThread
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 22.12.16 06:15
Оценка:
И ещё вопрос: как поместить в поток функцию, которая принимает не один, а скажем, четыре параметра?
1613 г. = 2024 г.
Re[6]: Работа с классом CWinThread
От: Evgeniy Skvortsov Россия  
Дата: 22.12.16 06:46
Оценка: 4 (1)
Здравствуйте, RussianFellow, Вы писали:

RF>И ещё вопрос: как поместить в поток функцию, которая принимает не один, а скажем, четыре параметра?


Передавай все параметры через LPVOID lpParameter, структуру создай, запихай в неё все параметры и адрес этой структуры отдавай функции потока.
Re: Работа с потоками (threads) в MFC
От: AlexGin Беларусь  
Дата: 22.12.16 18:07
Оценка: 4 (1)
Здравствуйте, RussianFellow, Вы писали:

RF>Не подскажете ли, уважаемые коллеги, как лучше всего работать с потоками (threads) в MFC?

_beginthreadex — в MSDN смотрим;
На крайний случай — AfxBeginThread (смотрим там же)

RF>Есть функция, производящая математические вычисления. Эта функция большая по длине и её действия происходят в цикле до выполнения некоего условия. Эта функция работает в консольном режиме--ввод и вывод данных там происходит с помощью консольного окна.

Условие — контролируем вызовом WinAPI-шной ::WaitForSingleObject
ну или же ::WaitForMultipleObjects — здесь зависит от того, имеется одно условие выхода из цикла или несколько.

RF>Как лучше поместить эту функцию в поток--использовать класс CWinThread, воспользоваться функцией AfxBeginThread или же использовать функции WinAPI для работы с потоками?

Правильнее всего — НЕ завязываться на CWinThread (избыточен он для данной задачи), вызывать _beginthreadex либо AfxBeginThread.
ВАЖНО: и в том и в другом случае "функция, производящая математические вычисления" должна быть глобальной или же статической,
если эта функция — просто метод класса, то данное решение работать НЕ БУДЕТ!
Отредактировано 23.12.2016 5:30 AlexGin . Предыдущая версия .
Re[2]: Работа с потоками (threads) в MFC
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 26.12.16 13:08
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>ВАЖНО: и в том и в другом случае "функция, производящая математические вычисления" должна быть глобальной или же статической,

AG>если эта функция — просто метод класса, то данное решение работать НЕ БУДЕТ!

Ясно.

И ещё вопрос: может ли поток (переменная типа HANDLE или CWinThread) быть членом класса?
1613 г. = 2024 г.
Re[3]: Работа с потоками (threads) в MFC
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 26.12.16 13:09
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>Здравствуйте, AlexGin, Вы писали:


AG>>ВАЖНО: и в том и в другом случае "функция, производящая математические вычисления" должна быть глобальной или же статической,

AG>>если эта функция — просто метод класса, то данное решение работать НЕ БУДЕТ!

RF>Ясно.


RF>И ещё вопрос: может ли поток (переменная типа HANDLE или CWinThread) быть членом класса?

Или указатель на поток (переменная типа HANDEL* или CWinThread*)?
1613 г. = 2024 г.
Re[4]: Работа с потоками (threads) в MFC
От: Evgeniy Skvortsov Россия  
Дата: 26.12.16 13:43
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>>И ещё вопрос: может ли поток (переменная типа HANDLE или CWinThread) быть членом класса?

RF>Или указатель на поток (переменная типа HANDEL* или CWinThread*)?

Конечно может, что может этому помешать?
Re[4]: Работа с потоками (threads) в MFC
От: AlexGin Беларусь  
Дата: 27.12.16 08:15
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>>И ещё вопрос: может ли поток (переменная типа HANDLE или CWinThread) быть членом класса?

RF>Или указатель на поток (переменная типа HANDEL* или CWinThread*)?
Может, конечно же, данная переменная быть членом класса.
Я упоминал только тот факт, что головная функция рабочего потока — не бывает членом класса.
Re: Как грамотно уничтожить поток в MFC
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 27.12.16 11:44
Оценка:
Как я понял, для запуска потока в MFC следует воспользоваться функциями AfxBeginThread или CreateThread или _beginthreadex, для приостановки выполнения потока следует воспользоваться функцией SuspendThread, для продолжения выполнения потока--функцией ResumeThread.

А как грамотно уничтожить поток в MFC?
Мне посоветовали функцию TerminateThread, но у неё есть недостатки--после её вызов поток всё равно занимает стек памяти и имеет доступ к ядру до своего завершения.
А как грамотно уничтожить поток, чтобы у него после этого уничтожения--чтобы после этого уничтожения этот поток не выполнялся, не имел доступа к ядру и не занимал стек памяти?

Есть функции AfxEndThread и ExitThread, вызываемые внутри функции потока для его завершения. Но как правильно их использовать?
И как правильно посылать сообщения потоку и как правильно поток должен принимать и обрабатывать эти сообщения?
1613 г. = 2024 г.
Re[2]: Как грамотно уничтожить поток в MFC
От: Слава  
Дата: 27.12.16 13:01
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>Есть функции AfxEndThread и ExitThread, вызываемые внутри функции потока для его завершения. Но как правильно их использовать?

RF>И как правильно посылать сообщения потоку и как правильно поток должен принимать и обрабатывать эти сообщения?

Посмотрите, как сделан дотнетовский CancellationToken и сделайте так же. В ходе вычислений поток может проверять состояние некоего volatile флага, и если он взведён, то завершать вычисление, прерывать цикл, рекурсию, и т.д. В общем случае, ничего уничтожать не надо. Поток сам завершится, когда выйдет из начальной функции, после чего его хэндл можно будет проверить чем-то вроде WaitForSingleObject с нулевым таймаутом и по коду возврата узнать, что поток завершён, после чего закрыть хэндл. Результат работы потока можно сложить в некую общую переменную, прогресс его работы можно тоже записывать в volatile переменную и периодически проверять из основного потока — по таймеру, например.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.