Std::vector не освобождает память в потоке

Если я создаю поток с _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> освободил память, когда она вышла за рамки?

Как измерить память? Вы уверены, что это не ложное срабатывание?

Some programmer dude 22.03.2022 17:35

Это не 200 КБ, скорее 200 МБ.

user17732522 22.03.2022 17:37
docs.microsoft.com/en-us/cpp/c-runtime-library/reference/… явно говорит, что вы не должны вызывать CloseHandle при использовании _beginthreadex.
Iziminza 22.03.2022 17:39

Ваш вызов _endthreadex убивает поток до того, как деструктор успевает запуститься.

freakish 22.03.2022 17:40

Даже если std::vector (и его распределитель) освобождает память, нет гарантии, что реализация operator new() освободит ее для хост-системы. Использование специфичных для ОС функций для управления потоками (таких как _beginthreadex()), которые не имеют отношения к реализации std::vector (или любого другого управления памятью, выполняемого стандартной библиотекой C++), еще менее вероятно приведет к освобождению памяти.

Peter 22.03.2022 17:40

Я предлагаю вместо этого использовать std::thread.

Some programmer dude 22.03.2022 18:04

Вместо std::vector? Почему?

JeffR 22.03.2022 18:04

Нет, вместо низкоуровневых функций многопоточности Windows. std::thread t(ThreadFunction, possible, arguments, to, the, thread, function); t.join();

Some programmer dude 22.03.2022 18:10

@JeffR - Разработчики стандартного компилятора C++ 11, который вы используете для Windows, уже проработали детали, в которых вы ошибаетесь. std::thread и соответствующие функции и классы делают все, что вы пытаетесь сделать, только правильно. Если для этого нет веских причин (например, вы используете компилятор C++98), используйте стандартные функции многопоточности и оставьте тяжелую работу по выяснению того, как реализовать std::thread, экспертам по компиляторам.

PaulMcKenzie 22.03.2022 18:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
75
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

C++ не знает, что вызов _endthreadex приводит к удалению потока. Таким образом, он не вызывает деструкторы локальных переменных, таких как asdf, до вызова _endthreadex.

Решение: не делайте этого. return 0; завершает поток и вызывает деструктор.

Но документы MS говорят звонить _endthreadex, если вы звоните _beginthreadex, или я неправильно их понял?

JeffR 22.03.2022 17:43

@JeffR «Вы можете явно вызвать _endthread или _endthreadex, чтобы завершить поток; однако _endthread или _endthreadex вызывается автоматически, когда поток возвращается из подпрограммы, переданной в качестве параметра в _beginthread или _beginthreadex»

user253751 22.03.2022 17:46

Как вы можете видеть в документация для _endthreadex, _endthreadex заставляет деструкторы C++, ожидающие в потоке, не вызываться.

Так что просто удалите вызов _endthreadex, и все будет в порядке.

Причины такого поведения объясняются в этот ответ.

Предложение «Завершение потока вызовом endthread или _endthreadex помогает обеспечить надлежащее восстановление ресурсов, выделенных для потока». сильно вводит в заблуждение, так как в вашем случае это скорее наоборот!

Iziminza 22.03.2022 17:48

Да, это очень заблуждение! Спасибо.

JeffR 22.03.2022 18:24

Другие вопросы по теме