Если я создаю поток с _beginthreadex
, а в потоке я использовал std::vector<WCHAR>
, который потребляет 200 МБ памяти - когда поток заканчивается, память не освобождается. Даже после CloseHandle
память не освобождается.
Вот рабочий пример:
#include <windows.h>
#include <process.h>
#include <vector>
using namespace std;
unsigned __stdcall Thread_RestartComputer(void* pComputerName)
{
std::vector<WCHAR> asdf(100000000);
_endthreadex(0);
return 0;
}
int main()
{
UINT threadID = 0;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &Thread_RestartComputer, 0, CREATE_SUSPENDED, &threadID);
ResumeThread(hThread);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
Я думал, что std::vector<WCHAR>
освободил память, когда она вышла за рамки?
Это не 200 КБ, скорее 200 МБ.
CloseHandle
при использовании _beginthreadex
.
Ваш вызов _endthreadex
убивает поток до того, как деструктор успевает запуститься.
Даже если std::vector
(и его распределитель) освобождает память, нет гарантии, что реализация operator new()
освободит ее для хост-системы. Использование специфичных для ОС функций для управления потоками (таких как _beginthreadex()
), которые не имеют отношения к реализации std::vector
(или любого другого управления памятью, выполняемого стандартной библиотекой C++), еще менее вероятно приведет к освобождению памяти.
Вместо std::vector? Почему?
Нет, вместо низкоуровневых функций многопоточности Windows. std::thread t(ThreadFunction, possible, arguments, to, the, thread, function); t.join();
@JeffR - Разработчики стандартного компилятора C++ 11, который вы используете для Windows, уже проработали детали, в которых вы ошибаетесь. std::thread
и соответствующие функции и классы делают все, что вы пытаетесь сделать, только правильно. Если для этого нет веских причин (например, вы используете компилятор C++98), используйте стандартные функции многопоточности и оставьте тяжелую работу по выяснению того, как реализовать std::thread
, экспертам по компиляторам.
C++ не знает, что вызов _endthreadex
приводит к удалению потока. Таким образом, он не вызывает деструкторы локальных переменных, таких как asdf
, до вызова _endthreadex
.
Решение: не делайте этого. return 0;
завершает поток и вызывает деструктор.
Но документы MS говорят звонить _endthreadex
, если вы звоните _beginthreadex
, или я неправильно их понял?
@JeffR «Вы можете явно вызвать _endthread или _endthreadex, чтобы завершить поток; однако _endthread или _endthreadex вызывается автоматически, когда поток возвращается из подпрограммы, переданной в качестве параметра в _beginthread или _beginthreadex»
Как вы можете видеть в документация для _endthreadex
, _endthreadex
заставляет деструкторы C++, ожидающие в потоке, не вызываться.
Так что просто удалите вызов _endthreadex
, и все будет в порядке.
Причины такого поведения объясняются в этот ответ.
Предложение «Завершение потока вызовом endthread
или _endthreadex
помогает обеспечить надлежащее восстановление ресурсов, выделенных для потока». сильно вводит в заблуждение, так как в вашем случае это скорее наоборот!
Да, это очень заблуждение! Спасибо.
Как измерить память? Вы уверены, что это не ложное срабатывание?