Cwinthread
От: ahaos  
Дата: 09.04.15 21:46
Оценка:
Здравствуйте!

Создается группа потоков, число которых равно числу ядер.

Ниже представлен упрощенный код.

CAVector<CWinThread*> pwth;
hnd.SetSize(GetCPUNumber());
pwth.SetSize(GetCPUNumber());

for (int i=1;i<=GetCPUNumber();i++)
{

//Создание потока расчета
pwth[i]=AfxBeginThread(CalculatePeriodicCukP,(LPVOID)pi,THREAD_PRIORITY_BELOW_NORMAL,NULL,CREATE_SUSPENDED);

if (pwth[i]==NULL)
{
AfxMessageBox ("Ошибка создания потока расчета");
return NULL;
}

pwth[i]->m_bAutoDelete=false;
pwth[i]->ResumeThread();

hnd[i]=pwth[i]->m_hThread;

}

//Ожидание конца расчета во всех потоках
HANDLE* mhnd;
mhnd=new HANDLE [hnd.GetSize()];

for (int i=1;i<=hnd.GetSize();i++)
mhnd[i-1]=hnd[i];

WaitForMultipleObjects(hnd.GetSize(),mhnd,true,INFINITE);


DWORD st;
for (int i = 1; i <= pwth.GetSize(); i++)
{
if (pwth[i] != NULL)
{
::TerminateThread(pwth[i]->m_hThread, st);
::CloseHandle(pwth[i]->m_hThread);
delete pwth[i];

}
}


Данная процедура происходит периодически и после достаточно большого количества итераций выдает сообщение "Ошибка создания потока расчета".
Поскольку используется m_bAutoDelete=false, то явно просматривается проблема некорректного удаления объекта CWinthread. Как это сделать корректно.
При попытке использования delete pwth[i] выдает ошибку. CAVector — самопальный массив.
Re: Cwinthread
От: Evgeniy Skvortsov Россия  
Дата: 10.04.15 08:38
Оценка:
Здравствуйте, ahaos, Вы писали:

Предлагаю создавать рабочие потоки напрямую через CreateThread или (_beginthread). В данном случае mfc-ые потоки не нужны.

А вообще странно что delete pwth[i] выдает ошибку. Кстати что за ошибка ?
Может оператор [] в самопальном массиве как-то криво реализован?

И кстати в цикле не нужны вызовы TerminateThread() и CloseHandle(). Первый — потому что поток уже завершился, второй — потому что CloseHandle вызывается в деструкторе CWinThread

А вообще можно сократить твой код до примерно такого:
        // Вектор не из голых указателей, а из смарт. Когда сам вектор будет уничтожен - он автоматом вызовет delete для указателей
    std::vector<std::unique_ptr<CWinThread*>> pwth;
        // вектор гарантирует что все элементы будут лежать в памяти в одном непрерывном куске памяти
        // так что создавать третий массив для WaitForMultipleObjects не требуется.
    std::vector<HANDLE> hnd;

    for (size_t i = 0; i <= GetCPUNumber; ++i)    {
        CWinThread *pthread = AfxBeginThread(proc, NULL, THREAD_PRIORITY_BELOW_NORMAL, NULL, CREATE_SUSPENDED);
        if (!pthread) {
            AfxMessageBox(_T("Ошибка создания потока расчета"));
            return;
        }
        pthread->m_bAutoDelete = false;
        pwth.push_back(std::make_unique<CWinThread*>(pthread));
        hnd.push_back(pthread->m_hThread);
        pthread->ResumeThread();
    }
    WaitForMultipleObjects(GetCPUNumber, &hnd[0], true, INFINITE);
Отредактировано 10.04.2015 9:51 Evgeniy Skvortsov . Предыдущая версия . Еще …
Отредактировано 10.04.2015 9:41 Evgeniy Skvortsov . Предыдущая версия .
Отредактировано 10.04.2015 8:55 Evgeniy Skvortsov . Предыдущая версия .
Re[2]: Cwinthread
От: rus blood Россия  
Дата: 15.04.15 20:41
Оценка:
Здравствуйте, Evgeniy Skvortsov, Вы писали:

ES> Кстати что за ошибка ?


Полагаю, 6, invalid handle...
Имею скафандр — готов путешествовать!
Re[3]: Cwinthread
От: Evgeniy Skvortsov Россия  
Дата: 16.04.15 06:22
Оценка:
Здравствуйте, rus blood, Вы писали:

RB>Полагаю, 6, invalid handle...


Логично, учитывая что перед удалением автор принудительно закрывает хэндл.
Но быстро глянув в исходники MFC вроде там не проверяется результат CloseHandle в деструкторе, как эта ошибка может себя проявить ?
Re: Cwinthread
От: Pavel Dvorkin Россия  
Дата: 20.04.15 02:57
Оценка:
Здравствуйте, ahaos, Вы писали:

A> pwth[i]=AfxBeginThread(CalculatePeriodicCukP,(LPVOID)pi,THREAD_PRIORITY_BELOW_NORMAL,NULL,CREATE_SUSPENDED);


A> delete pwth[i];


Еще бы. Закрывать поток надо AfxEndThread, а вовсе не delete

AfxBeginThread creates a new CWinThread object, calls its CreateThread function to start executing the thread, and returns a pointer to the thread. Checks are made throughout the procedure to make sure all objects are deallocated properly should any part of the creation fail. To end the thread, call AfxEndThread from within the thread, or return from the controlling function of the worker thread.

https://msdn.microsoft.com/ru-ru/library/s3w9x78e.aspx
With best regards
Pavel Dvorkin
Re[2]: Cwinthread
От: Evgeniy Skvortsov Россия  
Дата: 22.04.15 09:31
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Еще бы. Закрывать поток надо AfxEndThread, а вовсе не delete


Ни в коем случае. Эту функцию нужно звать только из того потока который хотим завершить. Там же в документации все четко расписано.
AfxBeginThread создает новый объект CWinThread при помощи обычного new. Если b_autodelete в потоке равно true, то после завершения рабочего потока, он сам себя уничтожает с использованием delete this.

В общем поток созданный с помощью CWinThread *t = AfxBeginThread с установленным b_autodelete = false, после завершения собственно потока нужно просто грохнуть delete t. И все, то что у ТС какие-то ошибки лезут — это что-то напортачено в другом месте.

Я приводил кусок кода со стандартным вектором и умным указателем — все работает и корректно удаляется.

И вообще, я еще раз повторю, что нафиг тут не уперлись MFC потоки. _beginthreadex или CreateThread в руки. Может в MFC баг какой-нибудь.
Re[3]: Cwinthread
От: Pavel Dvorkin Россия  
Дата: 22.04.15 10:06
Оценка:
Здравствуйте, Evgeniy Skvortsov, Вы писали:

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


PD>>Еще бы. Закрывать поток надо AfxEndThread, а вовсе не delete


ES>Ни в коем случае. Эту функцию нужно звать только из того потока который хотим завершить. Там же в документации все четко расписано.


Да, согласен. Тем не менее насчет delete там ничего нет.

ES>AfxBeginThread создает новый объект CWinThread при помощи обычного new. Если b_autodelete в потоке равно true, то после завершения рабочего потока, он сам себя уничтожает с использованием delete this.


Именно.

ES>И вообще, я еще раз повторю, что нафиг тут не уперлись MFC потоки. _beginthreadex или CreateThread в руки. Может в MFC баг какой-нибудь.


Да нет тут багов скорее всего, просто delete не нужен.

_beginthreadex можно, конечно. CreateThread не стоит — не поставишь в известность CRT, а она хочет знать о появлении нового потока.
With best regards
Pavel Dvorkin
Re[4]: Cwinthread
От: Evgeniy Skvortsov Россия  
Дата: 22.04.15 11:20
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Да, согласен. Тем не менее насчет delete там ничего нет.

Да, явно не написано что нужно звать delete, однако там есть такая фраза:

Set the m_bAutoDelete data member to FALSE. This allows the CWinThread object to survive after the thread has been terminated. You can then access the m_hThread data member after the thread has been terminated. If you use this technique, however, you are responsible for destroying the CWinThread object because the framework will not automatically delete it for you.


По моему очень прямой намек, что надо руками удалять экземпляр CWinThread.
Re[5]: Cwinthread
От: Pavel Dvorkin Россия  
Дата: 22.04.15 13:05
Оценка:
Здравствуйте, Evgeniy Skvortsov, Вы писали:

ES>По моему очень прямой намек, что надо руками удалять экземпляр CWinThread.


Если верить вот этому (а Alex Fedotov я верю)

http://rsdn.ru/forum/mfc/105994.1
Автор: Alex Fedotov
Дата: 25.09.02


то да, delete, но надо дождаться окончания потока.
With best regards
Pavel Dvorkin
Re[6]: Cwinthread
От: Evgeniy Skvortsov Россия  
Дата: 22.04.15 13:50
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>то да, delete, но надо дождаться окончания потока.


Дык у ТС все потоки завершаются ожиданием WaitForMultipleObjects.
Re[7]: Cwinthread
От: Pavel Dvorkin Россия  
Дата: 22.04.15 14:22
Оценка:
Здравствуйте, Evgeniy Skvortsov, Вы писали:

ES>Дык у ТС все потоки завершаются ожиданием WaitForMultipleObjects.


Тогда бог его знает.
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.