Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Почему нельзя освободить память из-под потока? FreeOnTerminate = true --> исключение 
:(
    Опции темы
ksili
Дата 12.3.2007, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



У меня один коротенький поток вызывается главным окном каждые 2 секунды. Логично освобождать из-под него память. Однако если FreeOnTerminate = true,  то возникает исключение примерно такого содержания:
"... raised exception class EOSError with message 'System Error. Code: 6. Неверный дескриптор'". Прямо так по-русски и пишет - неверный дескриптор.
В классе потока есть три перменные, но я вроде к ним нигде кроме как из самого потока не обращаюсь, тем более после его завершения.
В чём может быть проблема?
Что это за класс EOSError?


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Vyacheslav
Дата 12.3.2007, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Цитата(ksili @  12.3.2007,  10:54 Найти цитируемый пост)
коротенький поток вызывается главным окном каждые 2 секунды.

А после того, как отрабатывает, Вы его заново создаете?




--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
ksili
Дата 12.3.2007, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



Создаю его по событию таймера. Событие возникает каждые 3 секунды  (а не 2 как раньше написал, извиняюсь). За это время он успевает завершиться.

Но это наверно неважно, так как возникает исключение на первом же экземпляре потока (только не знаю именно в момент завершения или нет).

А вообще если он не успеет завершиться за 3 сек. И по таймеру будет создан второй поток, он не будет конфликтоватьс первым? Или это будет неправильно?

Это сообщение отредактировал(а) ksili - 12.3.2007, 11:13


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Vyacheslav
Дата 12.3.2007, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Без кода врядли что можно сказать путное


--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
ama_kid
Дата 12.3.2007, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


АСУТП-кодер
***


Профиль
Группа: Комодератор
Сообщений: 1460
Регистрация: 5.3.2007
Где: Москва

Репутация: 10
Всего: 95



Код, конечно, в таких вопросах ОБЯЗАТЕЛЬНО надо приводить... Навскидку можно предположить, что при завершении потока вызывается последовательность Thread1->Terminate и затем Thread1->Free (или как-то аналогично). При установленном свойстве FreeOnTerminate = true вторая команда фактически будет освобождать уже автоматически особожденный (при Terminate) участок памяти, что приводит к AV.


--------------------
самурай без меча подобен самураю с мечом, но только без меча 
PM MAIL   Вверх
ksili
Дата 12.3.2007, 11:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



Посмотрел в диспетчере задач без FreeOnTerminate = true. Вроде всё нормально один процесс создаётся и через некоторое время убивается. Память тоже освобождается и выделяется (больше не становится). Так что ложная тревога. Всем спасибо за внимание


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Vyacheslav
Дата 12.3.2007, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Цитата(ksili @  12.3.2007,  11:43 Найти цитируемый пост)
Посмотрел в диспетчере задач без FreeOnTerminate = true

А причем тут процессы smile Речь идет об уничтожении объекта класса после завершения процесса. То есть у Вас (если Вы конечно не уничтожаете  объект сами ) будет накапливаться утечка памяти.
Правда по завершению программы конечно все освободится ( WIn32 как никак smile ).  Но согласитесь, что такой подход некрасив : new без delete

Добавлено @ 13:21 
Цитата(ksili @  12.3.2007,  11:43 Найти цитируемый пост)
Память тоже освобождается и выделяется (больше не становится). 

Это Вы по диспетчеру задач определили ? Мда. А Вы не пробовали  спросить мнение на этот счет у CodeGuard? Думаю, он будет против. smile


--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
ksili
Дата 13.3.2007, 05:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



Так значит правильная последовательность работы с потоком примерно такая:
Код

td = new TDispThread(true);

td->hCom = All_chnls->chnls[i].pGSM;
td->Resume();

td->WaitFor();

delete td;

?

Если так написать, то память будет освобождаться и на флаг FreeOnTerminate можно не обращать внимание? Я правильно понял?

Это сообщение отредактировал(а) ksili - 13.3.2007, 07:37


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
pandrew
Дата 13.3.2007, 10:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 213
Регистрация: 27.3.2006

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



Для потока с FreeOnTerminate = true; завершение делается так:
Код

td->Terminate();
td->WaitFor();td=0;

Видимо если FreeOnTerminate = false; надо добавить delete td;
PM MAIL   Вверх
Vyacheslav
Дата 13.3.2007, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 2124
Регистрация: 25.3.2002
Где: Москва

Репутация: 47
Всего: 59



Цитата(ksili @  13.3.2007,  05:07 Найти цитируемый пост)
Так значит правильная последовательность работы с потоком примерно такая:

Идея то правильная.  И тут все будет очищаться правильно. Только в с логикой напряги.  Вы запускаете поток, а потом тормозите основной до момента, пока не выполнится дочерний. Смысл? Не проще тогда выполнить все действия в основном потоке? Все равно при работе дочернего он простаивает smile 
Я пока не могу понять одно. Почему у Вас не работает это ?
Код

td = new TDispThread(true);
td->FreeOnTerminate = true;
td->hCom = All_chnls->chnls[i].pGSM;
td->Resume();

Вы случаем после этих строчек не пытаетесь написать что-то вроде
Код

td->WaitFor();

или то, что  pandrew указал? Этого делать ни в коем случае нельзя. К моменту  обращения  к объекту td после того как уже вызван  Resume() поток может выполнится, а объект, соответственно, уничтожен  и Вы будете обращаться к несуществуещему объекту

Добавлено @ 13:17 
Цитата(pandrew @  13.3.2007,  10:27 Найти цитируемый пост)
Для потока с FreeOnTerminate = true; завершение делается так:

Грубая ошибка. Во-первых к моменту вызова Terminate поток может уже завершиться и td уничтожиться. Во-вторых, даже если поток еще работает, то он может успеть завершиться и уничтожиться после Terminate, но  до вызова  WaitFor.




--------------------
С уважением, Вячеслав Ермолаев
PM MAIL WWW ICQ   Вверх
ksili
Дата 13.3.2007, 13:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



Сейчас уже кода перед глазами нет, завтра погляжу повнимательнее и отвечу.
А почему нельзя после Resume() писать WaitFor()? Когда вообще тогда WaitFor() писать нужно?


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
dumb
Дата 13.3.2007, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 32
Всего: 158



ksili, сможешь аргументировать применение потоков в своей задаче?

Цитата(F1(WaitFor))

Waits for the thread to terminate and then returns the value of the ReturnValue property.

PM MAIL   Вверх
ksili
Дата 14.3.2007, 05:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



Я согласен, что WaitFor использовать в основном потоке неправильно, так как это тормозит всю прогу и сводит на нет все преимущество от использования потоков.

Теперь попробую аргументировать применение потоков в моей задаче.
В системе есть много COM-портов. Программа должна опрашивать те которые инициализированы (сейчас при отладке экспериментирую только с одним) на предмет того, что на них что-то поступило. Если поступило, то она сохраняет инфу об этом в специальной таблице БД. 
Есть ещё несколько потоков, которые периодически смотрят в эту таблицу и если там что-то есть, то отрабатывают это событие.

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

В общем эти действия (опрос порта и обработка поступившей  инфы) должна происходить не в основном потоке (реально портов будет не меньше 40), чтобы я во время всего этого мог работать с программой: инициализировать порт, освободить порт, смотреть журналы портов, смотреть текущую информацию о каналах  и т.д.

Я сейчас уже подумал, что правильнее будет не создавать эти потоки каждые 3 секунды, а создавать поток на каждый инициализированный порт, который будет его опрашивать постоянно:

Код

while(!Terminated)
    {
    ......
    }


Это сообщение отредактировал(а) ksili - 14.3.2007, 06:01


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Valeri
Дата 14.3.2007, 09:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 16
Регистрация: 2.2.2007

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



Привет 
у меня примерно такая же задача, но порт всего один. смысл тот же - время от времени для передачи в порт данных требуется приостановить поток сбора данных из порта. 
Сделал поток именно так как указано в предыдущем посте. Но не пойму почему не удается подвесить поток на время передачи в порт. Программа виснет. 

сам поток в таком виде работает нормально:

while(!Terminated)
        {

               if(WaitCommEvent(Form1->hCom,&dwCommEvent,NULL))               

                if(ClearCommError(Form1->hCom,&dwError,&COMSTAT))
                    dwRead=COMSTAT.cbInQue;
                                  {
                                          while (dwRead)
                                       {
        ReadFile(Form1-hCom   lpBuffer1,dwRead,lpNumberOfBytesWritten, NULL);
                        
                        Form1->Nsect=Form1->Data.RecByte1
                        Form1->Fh=(Form1->Data.RecByte2)+((Form1->Data.RecByte3)*255);
                                        
                        Form1->Label20->Caption=IntToStr(Form1->Data.RecByte1);
                        Form1->Label21->Caption=IntToStr(Form1->Data.RecByte2);
                        Form1->Label23->Caption=IntToStr(Form1->Data.RecByte3);
                        Form1->Label24->Caption=IntToStr(Form1->Fh);
                          
                                         }
                                   }
        }

но при попытке его подвесить из основного потока все виснет. 

PM MAIL   Вверх
ksili
Дата 14.3.2007, 09:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2069
Регистрация: 3.11.2005
Где: Красноярск

Репутация: 1
Всего: 17



Всё, что обращается к основной форме

Цитата(Valeri @  14.3.2007,  14:09 Найти цитируемый пост)
                        
Form1->Nsect=Form1->Data.RecByte1
                        Form1->Fh=(Form1->Data.RecByte2)+((Form1->Data.RecByte3)*255);
                                        
                        Form1->Label20->Caption=IntToStr(Form1->Data.RecByte1);
                        Form1->Label21->Caption=IntToStr(Form1->Data.RecByte2);
                        Form1->Label23->Caption=IntToStr(Form1->Data.RecByte3);
                        Form1->Label24->Caption=IntToStr(Form1->Fh);

надо поместить в отдельную функцию класса потока и вызывать её при помощи метода потока Synchronize. посмотри хелп на Synchronize


--------------------
Ничто так не развивает аналитическое мышление, как отладка сложной программы без возможности пошагового выполнения (с)
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


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

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


 




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


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

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