Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> удаление данных из TLS 
:(
    Опции темы
Lazin
Дата 15.4.2009, 08:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



Добрый день.
У меня есть такой код, и я недавно заметил, что здесь есть утечка памяти, а именно, не вызывается деструктор объекта после завершения не основного потока.
Код

            template <typename T>
            class thread_local
            {
            private:
                DWORD threadLocalIndex;

                thread_local(thread_local const&);

                T *get_pointer(void)
                {
                    return static_cast<T*>(::TlsGetValue(threadLocalIndex));
                }

                void set_pointer(T *value)
                {
                    ::TlsSetValue(threadLocalIndex, static_cast<void*>(value));
                }
            public:
                void set_value(const T &value)
                {
                    T* currentPointer = get_pointer();
                    if (currentPointer == NULL)
                    {
                        set_pointer(new T(value));
                    }
                    else
                    {
                        *currentPointer = value;
                    }
                }

                T &get_value()
                {
                    T* currentPointer = get_pointer();
                    if (currentPointer == NULL)
                    {
                        set_pointer(new T());
                    }
                    return *get_pointer();
                }

                operator T() 
                {
                    return get_value();
                }

                thread_local<T>& operator = (const T& value)
                {
                    set_value(value);
                    return *this;
                }

                void delete_value()
                {
                    T* currentPointer = get_pointer();
                    if (currentPointer != NULL)
                    {
                        delete currentPointer;
                        set_pointer(NULL);
                    }
                }

                thread_local(const T& value)
                {
                    threadLocalIndex = ::TlsAlloc();
                    set_value(value);
                }

                thread_local()
                {
                    threadLocalIndex = ::TlsAlloc();
                }

                ~thread_local()
                {
                    delete_value();
                    ::TlsFree(threadLocalIndex);
                }
            };

Здесь суть в следующем. Создается глобальный объект класса thread_local, который при создании вызывает TlsAlloc, и получает индекс. При первом обращении из потока, он создает новый объект и помещает указатель на него в TLS, потом возвращает все время его. При удалении объекта thread_local, удаляется объект размещенный в том потоке, в котором происходит удаление, но объекты созданные в других потоках остаются, потом вызывается ф-я tlsFree. Как можно удалить объект, указатель на который хранится в tls перед во время завершения потока?
PM MAIL Skype GTalk   Вверх
Lazin
Дата 15.4.2009, 09:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



в принципе, можно вызвать delete_value перед выходом из потока, можно использовать для этого RAII, но не хотелось-бы...
PM MAIL Skype GTalk   Вверх
GremlinProg
Дата 15.4.2009, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



можно в отдельном watch-потоке (или в пуле потоков) вызвать функцию ожидания, передав ей дескриптор потока, данные которого нужно удалить по завершению, ну и при ее срабатывании, удалить глобальные указатели потока, который завершился

проблема только в том, что нужно информировать этот watch-поток о создании новых потоков, за которыми нужно следить
т.е., при создании потока, его дескриптор нужно сразу передать в watch-поток или создать новый watch-поток (можно использовать пул потоков, так оптимальнее)

можно конечно использовать DLL и отслеживать моменты создания и удаления потоков в DLLMain'е, тогда и watch-потоки не нужны, но по-моему, этот вариант слишком накладный: таскать за собой DLL ради автоматического удаления потоковых объектов

проще всего, как это обычно и реализуется - обернуть функцию создания потока, например _beginthreadex и саму функцию потока
с соответствующими в них инициализацией и удалением потоковых данных


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Lazin
Дата 15.4.2009, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



нашел в бусте класс thread_specific_ptr, обещают что объект будет удаляться с помощью delete
PM MAIL Skype GTalk   Вверх
Lazin
Дата 15.4.2009, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



boost::thread_specific_storage работает так как мне нужно, правда я не понимаю как оно это делает, нужно будет это выяснить smile 
PM MAIL Skype GTalk   Вверх
GremlinProg
Дата 15.4.2009, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



это как раз вариант с оберткой _beginthreadex:
Код

    void thread::start_thread()
    {
        uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
        if(!new_thread)
        {
            throw thread_resource_error();
        }
        intrusive_ptr_add_ref(thread_info.get());
        thread_info->thread_handle=(detail::win32::handle)(new_thread);
        ResumeThread(thread_info->thread_handle);
    }


 и функции потока:
Код

        unsigned __stdcall thread_start_function(void* param)
        {
            detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
            set_current_thread_data(thread_info);
            try
            {
                thread_info->run();
            }
            catch(thread_interrupted const&)
            {
            }
// Removed as it stops the debugger identifying the cause of the exception
// Unhandled exceptions still cause the application to terminate
//             catch(...)
//             {
//                 std::terminate();
//             }
            run_thread_exit_callbacks();
            return 0;
        }


set_current_thread_data - инициализация
run_thread_exit_callbacks - вызов всех ассоциированных callback'ов ну и попутное освобождение потоковых данных, если таковые были
очевидно, есть свободные методы регистрации callback'ов
отсюда можно плясать дальше, только для реализации такого механизма привязываться к boost'у совсем не обязательно


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0467 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.