Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Потоки в DLL


Автор: aktuba 2.2.2007, 08:38
Люди, я тупею со страшной скоростью  smile 
Есть такая задача: необходимо создать dll-файл, в котором присутствуют функции запросов по http в потоках. Т.е. программа подключает dll, вызывает необходимую функцию http (get или post). Dll в свою очередь создает поток, в котором создает IdHTTP и выполняет необходимый запрос. После выполнения запроса возвращает результат. Все это необходимо для того, чтобы я мог из программы одновременно создать 10 http-запросов, которые выполнялись бы параллельно. Вот тут у меня тупик (наверное сказывается пара дней без сна). Вот что имею:

Модуль потока:
Код

unit uThread;

interface

uses
  Classes,
  SysUtils,
  IdHTTP,
  IdCookieManager;

type
  THTTPThread = class(TThread)
  private
    { Private declarations }
    FUrl: string;
    FParams: TStrings;
    FResult: string;
    FCommand: string;
    FResultCode: Cardinal;
    FHTTP: TIdHTTP;
    FCookie: TIdCookieManager;
    procedure Get;
    procedure PostStrings;
  protected
    procedure Execute; override;
  end;

implementation

uses
  uConsts;

{ HTTPThread }

procedure THTTPThread.Execute;
begin
  FResult := '';
  FResultCode := ErrNo;
  FHTTP := TIdHTTP.Create(nil);
  FCookie := TIdCookieManager.Create(nil);
  try
    FHTTP.CookieManager := FCookie;
    FCommand := LowerCase(FCommand);
    if FCommand = 'get' then Get else
    if FCommand = 'post' then PostStrings else
    FResultCode := ErrCommand;
  finally
    FreeAndNil(FCookie);
    FreeAndNil(FHTTP);
  end;
end;

procedure THTTPThread.Get;
begin
  FResult := '';
  FResultCode := ErrGet;
  if not Assigned(FHTTP) then
    begin
      FResultCode := ErrInit;
      Exit;
    end;
  try
    FResult := FHTTP.Get(FUrl);
    if FResult = ''
      then FResultCode := ErrTimeout
      else FResultCode := ErrNo;
  except
    FResultCode := ErrConnect;
  end;
end;

procedure THTTPThread.PostStrings;
begin
  FResult := '';
  FResultCode := ErrPost;
  if not Assigned(FHTTP) then
    begin
      FResultCode := ErrInit;
      Exit;
    end;
  try
    FResult := FHTTP.Post(FUrl, FParams);
    if FResult = ''
      then FResultCode := ErrTimeout
      else FResultCode := ErrNo;
  except
    FResultCode := ErrConnect;
  end;
end;

end.


Модуль Dll:
Код

unit uInet;

interface

uses
  Classes,
  uConsts;

procedure Init(Timeout: Cardinal);
function GetError(ACode: Cardinal): string;
function Get(const AUrl: string; out AReq: string): Cardinal;
function PostStrings(const AUrl: string; AParams: TStringList; out AReq: string): Integer;

var
  FInit: Boolean;
  FTimeout: Cardinal;

implementation

procedure Init(Timeout: Cardinal);
begin
  FTimeout := Timeout;
  FInit := True;
end;  

function GetError(ACode: Cardinal): string;
begin
  case ACode of
    ErrNo:          Result := StrErrNo;
    ErrConnect:     Result := StrErrConnect;
    ErrCommand:     Result := StrErrCommand;
    ErrInit:        Result := StrErrInit;
    ErrTimeout:     Result := StrErrTimeout;
    ErrInitModule:  Result := StrErrInitModule;
    ErrGet:         Result := StrErrGet;
    ErrPost:        Result := StrErrPost;
  else Result := StrErrNotFound;
  end;
end;

function Get(const AUrl: string; out AReq: string): Cardinal;
begin
  if not FInit then
    begin
      Result := ErrInitModule;
      Exit;
    end;
  Result := 0;
  AReq := '';

end;

function PostStrings(const AUrl: string; AParams: TStringList; out AReq: string): Integer;
begin
  if not FInit then
    begin
      Result := ErrInitModule;
      Exit;
    end;
  Result := 0;
  AReq := '';
  
end;  

end.


Я не могу понять, как сделать так, чтобы при каждом вызове функция Get или PostStrings создавался новый поток, но не терялся старый...
Поставьте меня plz на путь истинный... smile 

Автор: Romikgy 2.2.2007, 10:33
Я бы создал в длл динамический список хенделов потоков 
да и вообще те чет надо придумать с асинхроным приходом ответов с сайтов имхо

Автор: aktuba 2.2.2007, 10:36
Цитата

Я бы создал в длл динамический список хенделов потоков 
да и вообще те чет надо придумать с асинхроным приходом ответов с сайтов имхо 


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

Автор: Romikgy 2.2.2007, 10:47
Цитата(aktuba @  2.2.2007,  09:36 Найти цитируемый пост)
На счет динамического списка - есть такая мысль, вот только как правильно реализовать?

при запуске потока , первые строки заносят в глобальный список потоков, хендл себя,
при окончании потока , свой хендл вычеркивает из списка smile
Цитата(aktuba @  2.2.2007,  09:36 Найти цитируемый пост)
А насчет асинхронного - вообще связываться не хочу, если честно.... 

хы , а терь представь у тя 2 сайта, 1 грузиться быстро , второй медленно,
в длл запускаются 2 потока, (кса я так и не понял с ответом из длл)
как я понимаю управления после запуска потоков передается основной проге( потоку) 
и с 1 сайта уже скачалось и ответ попал в ответый стринг , а со второго еще качается,
как ты думаешь когда инфа закачается со второго сайта, кому она ответ передаст?

Автор: aktuba 2.2.2007, 10:51
Цитата

Цитата(aktuba @  2.2.2007,  09:36 Найти цитируемый пост)
На счет динамического списка - есть такая мысль, вот только как правильно реализовать?

при запуске потока , первые строки заносят в глобальный список потоков, хендл себя,
при окончании потока , свой хендл вычеркивает из списка smile
Цитата(aktuba @  2.2.2007,  09:36 Найти цитируемый пост)
А насчет асинхронного - вообще связываться не хочу, если честно.... 

хы , а терь представь у тя 2 сайта, 1 грузиться быстро , второй медленно,
в длл запускаются 2 потока, (кса я так и не понял с ответом из длл)
как я понимаю управления после запуска потоков передается основной проге( потоку) 
и с 1 сайта уже скачалось и ответ попал в ответый стринг , а со второго еще качается,
как ты думаешь когда инфа закачается со второго сайта, кому она ответ передаст? 


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

Можно как-то проще сделать?

Автор: Romikgy 2.2.2007, 11:04
Цитата(aktuba @  2.2.2007,  09:51 Найти цитируемый пост)
программа вызывает функцию передавая свой хендл

зачем это ?
Цитата(aktuba @  2.2.2007,  09:51 Найти цитируемый пост)
Можно как-то проще сделать? 

для твоего случая имхо ни как

Автор: aktuba 2.2.2007, 11:17
Цитата

зачем это ?


Как это зачем? Мне же надо сообщить программе что запрос обработан. Значит надо знать, куда слать сообщение...

Автор: CatATonik 2.2.2007, 13:39
Может лучше потоку передавать указатель на CallBack функцию? Типа поток отработал, вызвал функцию передал ей текст ответа и код ошибки.

Автор: MetalFan 3.2.2007, 15:45
тоже думал над подобно "проблемой")
значит какие мысли)
объекты/процедуры:
1) вызывающая программа(App), 
* список, в котором будут "объекты-отправители-запросов" (THttpRequests
* сам класс "отправитель", THttpRequest
* Callback процедура вида SendThreadCallbackEnd( AppContext: dword; ResultSize: dword);


2) библиотека (Lib), 
* "поток-непосредственный отправитель". например TDllSendThread
* процедура создания "потока-отправителя" вида procedure CreateInitSendThread( AppContext: dword; AData: pointer; ADataSize: dword; var ALibContext: dword );
* процедура инициализации библиотеки. procedure InitLib( AppCallback: TAppCallback); которая в контексте библиотеки сохраняет указатель на callback процедуру из App
* процедура получения данных из DLL, LibGetData( ALibContext: dword; ABuf: pointer; ABufSize: dword;var AReadSize: dword );

что как работает:
* инициализируем Lib
послать данные
1) список создает элемент THttpRequest
 в котором вызывается функция CreateInitSendThread передается указатель-контекст на созданный класс THttpRequest(его надо запомнить в созданном в библиотеке TDllSendThread) и отдаются некоторые данные в DLL(запрос, параметры и проч), возвращается конекст-указатель на класс TDllSendThread в библиотеке. в принципе если он уже запущен, то все. ушли забыли покачто.
2) в TDllSendThread отрабатывает запрос в Execute, "дергает" SendThreadCallbackEnd, в которую передает запомненный AppContext и размер буфера, необходимого для размещения ответа.
3) в  App в SendThreadCallbackEnd приводится к THttpRequest(Pointer(AppContext)) и вызывается PrepareGetData, в которой выделяется необх буфер и вызывается LibGetData...

ну в обчем мысль такая. немножко мурено, но идея вроде правильная) сам реализовывал нечто похожее, только потоки у меня были в самом приложении и вызывали функции из длл... что требовало создания служебных объектовс так называемыми "контекстами" внтури dll.
p.s. конечно же не забываем про потокобезопасность! все критические участки кода (SendThreadCallbackEnd например) в критические секции  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)