Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.03.2010, 17:31   #1
Zuzlan
Пользователь
 
Регистрация: 01.11.2007
Сообщений: 19
Вопрос Если остановился поток (TThread). Как перезапустить без потери памяти

Здравствуйте, уважаемые
Прошу помощи, уже замучался совершенно

Описание:
существует огромный проект (с многопоточностью), в нем используются IdHTTP c TIdIOHandlerSocket и TIdSocksInfo (для работы через socks4/5)
Использую Indy9 (обновлять не могу, уже привык к существующим ошибкам в этой либе (с которыми знаком))

Время от времени соксы умирают, но проблема в том, что поток при этом не двигается дальше. В варианте с простыми HTTP Proxy я мог сделать IdHTTP.DisconnectSocket и это решало проблему - Get (Post) прерывали свою работу и поток работал дальше. Но при подключении TIdIOHandlerSocket и TIdSocksInfo этот вариант больше не срабатывает (ошибок не возникает, поток просто останавливается и находится в подвисшем состоянии до остановки программы).


Собственно вопрос:
Как можно убить подвисший поток (рассмотрю любые альтернативные варианты к данной ситуации)?
Острые моменты:
1. При попытке пересоздания экземпляра класса безвозмездно теряется память.
2. Возникает Access Violation (что совершенно логично)


Подскажите, пожалуйста, выход из ситуации. За ранее огромное спасибо!
Zuzlan вне форума Ответить с цитированием
Старый 28.01.2011, 21:00   #2
Wadimka
Пользователь
 
Регистрация: 03.02.2009
Сообщений: 20
По умолчанию

И мне это тоже нужно, вернее как перезапустить отработанный поток, чтоб не потерялись данные, хотя можно и с потерями, главное не пересоздавать, а просто перезапустить его Execute?
Wadimka вне форума Ответить с цитированием
Старый 28.01.2011, 21:46   #3
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Цитата:
Сообщение от Wadimka Посмотреть сообщение
И мне это тоже нужно, вернее как перезапустить отработанный поток, чтоб не потерялись данные, хотя можно и с потерями, главное не пересоздавать, а просто перезапустить его Execute?
В потоке делаем цикл. Создаем мютекс. Ставим на вечное ожидание через WaitForSingleObject. В месте в котором где нужно перезапустить поток устанавливаем мютекс потока, что в свою очередь даст отработать WaitForSingleObject и поток в очередной раз выполнит итерацию цикла.
BOBAH13 вне форума Ответить с цитированием
Старый 30.01.2011, 12:32   #4
InternetStranger
php / delphi
Форумчанин
 
Аватар для InternetStranger
 
Регистрация: 10.06.2007
Сообщений: 175
По умолчанию

+1. Потоку не нужно давать отрабатывать (завершиться).
Можно и без Мьютексов (правда с двумя флагами) при помощи нехитрой конструкции:
Код:
procedure Thread.Execute;
begin
     repeat
         if (РазрешитьВыполнение) then begin
              КонецИтерации:= False;
              ...
              КонецИтерации:= True;
         end;
     until False;
end;

// Тогда команда возобновления работы выглядит так
procedure Start;
begin
    РазрешитьВыполнение := True; // Открываем флаг для итераций
    Suspended := False;                // Разбудим поток  
end;


// А команда приостановки работы
procedure Pause;
begin
    РазрешитьВыполнение := False; // Закрываем флаг, чтобы новые итерации больше не выполнялись
    repeat until КонецИтерации;      // Дожидаемся пока завершится последняя (текущая) итерация
    Suspended := True;                  // Усыпляем поток
end;
ps: Ощущение на душе, что корявенько, но работает безотказно =)
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра.
InternetStranger вне форума Ответить с цитированием
Старый 30.01.2011, 13:01   #5
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Код:
repeat
         if (РазрешитьВыполнение) then begin
              КонецИтерации:= False;
              ...
              КонецИтерации:= True;
         end;
     until False;
Подобная конструкция:
1. Велосипед
2. Повесит поток, загрузит на 100%

Почему мютекс:
1. Системное решение
2. Останавливает поток на время, в ожидании сигнала от мютекса
BOBAH13 вне форума Ответить с цитированием
Старый 30.01.2011, 13:20   #6
InternetStranger
php / delphi
Форумчанин
 
Аватар для InternetStranger
 
Регистрация: 10.06.2007
Сообщений: 175
По умолчанию

Не спорю - действительно Велосипед.
Цитата:
2. Повесит поток, загрузит на 100%
В каком смысле повесит? Работающий поток и должен нагружать проц.
Флаг РазрешитьВыполнение предполагается использовать только совместно с Suspended. Никто и не предлагает крутить поток вхолостую. Для этого и привел соответствующие методы управления потоком. При их использовании поток вхолостую крутится лишь незначительное время.

Цитата:
2. Останавливает поток на время, в ожидании сигнала от мютекса
Интересно как выглядит упомянутый процесс ожидания. И при этом не нагружает проц? Не могли бы примерный код набросать/привести? Если все так радужно - хотелось бы взять на вооружение.
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра.
InternetStranger вне форума Ответить с цитированием
Старый 30.01.2011, 13:59   #7
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Цитата:
Сообщение от InternetStranger Посмотреть сообщение
Не спорю - действительно Велосипед.

В каком смысле повесит? Работающий поток и должен нагружать проц.
Флаг РазрешитьВыполнение предполагается использовать только совместно с Suspended. Никто и не предлагает крутить поток вхолостую. Для этого и привел соответствующие методы управления потоком. При их использовании поток вхолостую крутится лишь незначительное время.


Интересно как выглядит упомянутый процесс ожидания. И при этом не нагружает проц? Не могли бы примерный код набросать/привести? Если все так радужно - хотелось бы взять на вооружение.
Уже писал, это WaitForSingleObject. Читаем разбираемся с данной API.
BOBAH13 вне форума Ответить с цитированием
Старый 31.01.2011, 13:31   #8
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Цитата:
Интересно как выглядит упомянутый процесс ожидания. И при этом не нагружает проц? Не могли бы примерный код набросать/привести?
ожидание на уровне ядра, система видит что поток находится в ожидании и не дает ему кванта времени.
Цитата:
1. При попытке пересоздания экземпляра класса безвозмездно теряется память.
если класс правильно сформулирован то потерь памяти е будет.
Цитата:
2. Возникает Access Violation (что совершенно логично)
не вижу логики.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 01.02.2011, 07:44   #9
Zuzlan
Пользователь
 
Регистрация: 01.11.2007
Сообщений: 19
По умолчанию

Здравствуйте, Пепел Феникса

Из ситуации я вышел обходным путем, в корне исключив использование библиотеки Indy в cвоих проектах и изменил подход в плане организации структуры многопоточных проектов.
Но на поставленный мной выше вопрос я до сих пор не смог бы ответить.

Вижу в этом вопросе вы значительно эрудированнее меня, поэтому поясню ситуацию на пальцах, надеюсь вы укажите мне на мои ошибки.

Итак, внутри потока:
Код:
procedure ProxyThread.Execute;
begin
  ht:=TIdHTTP.Create(nil);
  sock:=TIdSocksInfo.Create(nil);
  io:=TIdIOHandlerSocket.Create(nil);
  try
    try
	  io.SocksInfo:=sock;
	  HT.IOHandler:=io;
	  HT.Socket.SocksInfo.Version:=svSocks4;
	  HT.Socket.SocksInfo.Host:=GetHost;
	  HT.Socket.SocksInfo.Port:=GetPort;   
	  page:=HT.Get(SomePage); 
    except
    end;
  finally
    io.free;
    sock.free;
    ht.free;
  end;
end;
т.е. то что я создал - то я и уничтожаю.

теперь представим, что у меня 100 экземпляров этого класса и каждый получает сокс для проверки. После завершения работы экземпляр пересоздается и так далее.

Если качество наших соксов превосходное, то даже за несколько часов работы мы не увидим роста выделенной памяти под процесс.

Другое дело, когда проверяться начинают доступные в паблике и очень плохого качества соксы - тут и начинаются проблемы. Уже через несколько минут видим, что работают не все наши 100 потоков, а лишь какая-то малая часть из них. Причем можно отследить как выполнение в потоке доходит до функции:
Код:
page:=HT.Get(SomePage);
, но дальше не идет, где-то там IdHTTP безконечно ожидает ответа от сервера..
Замечу очень важный момент: свойства Timeout игнорируются в принципе, а DisconnectSocket попросту не работает когда мы используем соксы (подключая TIdSocksInfo и TIdIOHandlerSocket).

Останавливаем перезапуск потоков, видим на счетчике 87 активных потоков и уходим на пару часов. Возвращаемся, и на счетчике видим примерно тоже число незавершившихся потоков. Что делать? Что тут в принципе можно сделать?

Вариантов перепробовал море, все что приходиол только в голову.

TerminateThread ? - теряется память
Попытка сделать MyThread.Free ? - ерунда и глупость

MyThread.HT.Free
MyThread.io.Free
MyThread.sock.Free ? - получаем Access Violation. Почему я сказал, что - это логично? Потому что они работают в текущий момент. Но проблема не в ошибке, а в том что теряем память.

И что у меня получается ошибочным в таком построении класса и где я не прав? Главное - как завершить такой поток не потеряв при этом память?
Zuzlan вне форума Ответить с цитированием
Старый 01.02.2011, 13:57   #10
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

Код:
procedure ProxyThread.Execute;
begin
  ht:=TIdHTTP.Create(nil);
  sock:=TIdSocksInfo.Create(nil);
  io:=TIdIOHandlerSocket.Create(nil);
  try
    try
	  io.SocksInfo:=sock;
	  HT.IOHandler:=io;
	  HT.Socket.SocksInfo.Version:=svSocks4;
	  HT.Socket.SocksInfo.Host:=GetHost;
	  HT.Socket.SocksInfo.Port:=GetPort;   
	  page:=HT.Get(SomePage); 
    except
    end;
  finally
    io.free;
    sock.free;
    ht.free;
  end;
end;
красное выносим в конструктор потока.
салатовое в деструктор.
там же вы можете поместить поля для хоста и порта.

итого:
Код:
  TProxyThread = class(TThread)
  private
    sock:TIdSocksInfo;
    HT:TIdHTTP;
    io:TIdIOHandlerSocket;
  protected
    procedure Execute; override;
  public
    constructor Create(ACreateSuspended:boolean;APort:integer;AHost:string);
    destructor Destroy;override;
  end;

constructor TProxyThread.Create;
begin
 inherited Create(true);
 HT:=TIdHTTP.Create(nil);
 io:=TIdIOHandlerSocket.Create(nil);
 sock:=TIdSocksInfo.Create(nil);
 io.SocksInfo:=sock;
 HT.IOHandler:=io;
 HT.Socket.SocksInfo.Version:=svSocks4;
 HT.Socket.SocksInfo.Host:=AHost;
 HT.Socket.SocksInfo.Port:=APort;
 if(not ACreateSuspended)then Resume;
end;

destructor TProxyThread.Destroy;
begin
 Suspend;
 HT.Free;
 io.FREE;
 sock.FRee;
 inherited Destroy;
end;

procedure ProxyThread.Execute;
begin
  try
   page:=HT.Get(SomePage); 
  except
  end;
end;
примерно так.
проверить не могу, у меня нет ни инди, ни проксь
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как оповестить основной поток о каком-то событии в потоке (TThread)? TwiX Общие вопросы Delphi 2 11.02.2010 02:57
Delphi: как поместить анимацию (без звука) в отдельный поток? ex.cluz Помощь студентам 0 15.01.2010 14:26
Отобразить рабочий поток (TThread) NervniiJ Общие вопросы Delphi 0 10.01.2010 17:34
Убрать точки без потери данных king13 Microsoft Office Excel 4 07.10.2009 13:54
Копирование таблицы без потери форматирования k1r1ch Microsoft Office Excel 3 09.07.2009 11:00