Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 22.04.2015, 18:49
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию Как сделать однопоточный проект многопоточным

В общем считаю нужным создать другую тему, потому как название старой уже совсем не соответствует возникшим вопросам. Написал рабочий однопоточный проект, теперь пытаюсь сделать его многопоточным, прочитал уже кучу инфы, но что-то не выходит у меня. Вроде бы получается создать потоки, но дальше вылетает ошибка "Socket Error. Socket is not connected". Хотя в один поток всё работает отлично. Я так понимаю. что нужно как-то синхронизировать потоки между собой. На данный момент код выглядит так:
Код:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, sSkinManager, StdCtrls, sButton, ComCtrls, acProgressBar, sMemo,
  sLabel, sEdit, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdHTTP, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL,
  IdCookieManager, IdIntercept, IdCompressionIntercept, sDialogs, sSpinEdit;

type
  TForm2 = class(TForm)
    sMemo1: TsMemo;
    sButton1: TsButton;
    IdHTTP1: TIdHTTP;
    IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
    sEdit3: TsEdit;
    sLabel3: TsLabel;
    sLabel4: TsLabel;
    sLabel5: TsLabel;
    sMemo2: TsMemo;
    sButton2: TsButton;
    sOpenDialog1: TsOpenDialog;
    sLabel6: TsLabel;
    sLabel7: TsLabel;
    sLabel8: TsLabel;
    sLabel9: TsLabel;
    sSkinManager1: TsSkinManager;
    sProgressBar1: TsProgressBar;
    sButton3: TsButton;
    sSpinEdit1: TsSpinEdit;
    sLabel1: TsLabel;
    procedure sButton1Click(Sender: TObject);
    procedure sButton2Click(Sender: TObject);
    procedure sButton3Click(Sender: TObject);
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMyThread = class(TThread)
  private
  protected
  procedure WriteFile;
  procedure Good;
  procedure Bad;
  procedure ProgressBar;
  procedure MemoClear;
    procedure Execute; override;
end;


var
  Form2: TForm2;
  Accounts: TStringList;
  Login, Password, del: string;
  ProgressPos: integer;
  T1: TThread;

implementation

{$R *.dfm}


procedure TForm2.sButton2Click(Sender: TObject);
begin
Accounts:=TStringList.Create;
if sOpenDialog1.Execute then
begin
  Accounts.Clear;
  sMemo1.Lines.Clear;
  sMemo2.Lines.Clear;
  Accounts.LoadFromFile(sOpenDialog1.FileName);
  sLabel9.Caption:=inttostr(Accounts.Count);
  end;
if pos(';', Accounts.Strings[0])<>0 then
begin
  del:=';';
end else
begin
del:=':';
 end;
end;


procedure TForm2.sButton3Click(Sender: TObject);
begin
T1.Terminate;
Form2.sProgressBar1.Position:=Accounts.Count;
end;

procedure TForm2.sButton1Click(Sender: TObject);
{var
Threads: integer;
begin
for
Threads:=1  to sSpinEdit1.Value do}
begin
T1:=TMyThread.Create(False);
T1.Priority:=tpLower;
end;
{end;}

procedure TMyThread.MemoClear;
begin
 Form2.sMemo1.Lines.Clear;
 Form2.sMemo2.Lines.Clear;
end;


procedure TMyThread.ProgressBar;
begin
 Form2.sProgressBar1.Position:=ProgressPos+1;
 Form2.sProgressBar1.Max:=Accounts.Count;
end;


procedure TMyThread.Bad;
begin
 Form2.sMemo2.Lines.Add(Login+del+Password);
 Form2.sLabel6.Caption:=inttostr(Form2.sMemo2.Lines.Count);
end;


procedure TMyThread.Good;
begin
 Form2.sMemo1.Lines.Add(Login+del+Password);
 Form2.sLabel7.Caption:=inttostr(Form2.sMemo1.Lines.Count);
end;

procedure TMyThread.WriteFile;
begin
 Form2.sMemo1.Lines.SaveToFile(ExtractFilePath(Application.ExeName) + 'Good.txt');
 Form2.sMemo2.Lines.SaveToFile(ExtractFilePath(Application.ExeName) + 'Bad.txt');
end;




procedure TMyThread.Execute;
  var
  HTML: string;
  Acc: integer;
begin;
Synchronize(MemoClear);
for Acc := 0 to Accounts.Count-1 do
 begin
 if Terminated
 then break;
 ProgressPos:=Acc;
 Synchronize(ProgressBar);
 Login:=copy(Accounts[Acc], 1, pos(del, Accounts[Acc])-1);
 Password:=copy(Accounts[Acc], pos(del, Accounts[Acc])+1, MaxInt);
 HTML:=Form2.IdHTTP1.Get('http://xxxxxx'+Login+'xxxxxx'+Password);
  if pos ('class="xxxxxx"', HTML)<>0 then
  if Form2.sEdit3.Text<>'' then
  begin
   HTML:=Form2.IdHTTP1.Get('https://xxxxxx'+Form2.sEdit3.Text+'xxxxxx');
   if pos ('class="xxxxxx"', HTML)<>0 then
    begin
     Synchronize(Bad);
    end
    else
    begin
     Synchronize(Good);
    end
  end
  else
  begin
     Synchronize(Good);
  end
else
begin
Synchronize(Bad);
end;
Synchronize(WriteFile);
end;

end;


end.

Последний раз редактировалось AlexBerg001, 23.04.2015 в 14:01.
Ответить с цитированием
  #2  
Старый 22.04.2015, 21:49
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,096
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Ох ты ж елки...
Естесвенно, не работает.
Либо ты делаешь ограничение на доступ к IdHTTP из потока (см. CriticalSection), либо у каждого потока надо создать свой экземпляр IdHTTP.
Да и вообще, если просто хочешь обрабатывать список в несколько потоков, надо менять внутреннюю архитектуру приложения.
Кратко:
1. Основной поток создает очередь заданий, пул потоков (не рекомендую создавать больше 10 для начала), запускает потоки и ждет пока они все не обработают (тут есть варианты реализации, в зависимости от того, что хочется).
2. Поток смотрит в очередь (CriticalSection), если там есть задание, то берет одно и начинает его выполнять, по результату отправляет сообщение в основной поток (опять CriticalSection или использовать виндовые сообщения). Если заданий нет, то либо засыпает на какое-то время, либо "умирает" (зависит от реализации хотелок).
3. Основной поток при получении сообщения от потока выводит результат пользователю.
Ответить с цитированием
  #3  
Старый 23.04.2015, 10:48
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Вы конечно всё замечательно объяснили, но у меня что-то не выходит создать IdHTTP в потоке, дальше я ещё не продвинулся. Можете поконкретнее объяснить как это можно реализовать? Это вообще мой первый проект, вот пытаюсь как-то сделать что-то толковое)
И почему "ох ты ж ёлки"? Разве криво написано для однопотока?
И ещё одна беда, когда в глобальные var добавляю CS: TCriticalSection, в OnCreate формы CS:=TCriticalSection.Create вылезает ошибка Undeclared Identifier TCriticalSection. В чём ошибка-то не пойму?

Последний раз редактировалось AlexBerg001, 23.04.2015 в 14:42.
Ответить с цитированием
  #4  
Старый 24.04.2015, 12:40
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Короче разобрался немного вроде, просто добавил не TCriticalSection, а TRTLCriticalSection, получилось вот так:
Код:
var
  Form2: TForm2;
  Accounts: TStringList;
  Login, Password, del: string;
  ProgressPos: integer;
  T1: TThread;
  CS: TRTLCriticalSection;

procedure TForm2.FormCreate(Sender: TObject);
begin
CS:=TRTLCriticalSection.Create;
end;
Теперь почему-то вообще ругается вот так "Undeclared identifier: 'Create'". Что здесь не так, я что-то вообще не могу понять
Ответить с цитированием
  #5  
Старый 24.04.2015, 14:08
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

потому что:
Код:
  _RTL_CRITICAL_SECTION = record
    DebugInfo: PRTLCriticalSectionDebug;
    LockCount: Longint;
    RecursionCount: Longint;
    OwningThread: THandle;
    LockSemaphore: THandle;
    Reserved: DWORD;
  end;
  TRTLCriticalSection = _RTL_CRITICAL_SECTION;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #6  
Старый 24.04.2015, 15:43
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Цитата:
Сообщение от NumLock
потому что:
Код:
  _RTL_CRITICAL_SECTION = record
    DebugInfo: PRTLCriticalSectionDebug;
    LockCount: Longint;
    RecursionCount: Longint;
    OwningThread: THandle;
    LockSemaphore: THandle;
    Reserved: DWORD;
  end;
  TRTLCriticalSection = _RTL_CRITICAL_SECTION;
Вы меня конечно извините за мою некомпетентность, но я вообще ничего не понял, вы можете нормально объяснить что этот код делает и куда его вставлять-то?
Ответить с цитированием
  #7  
Старый 24.04.2015, 16:08
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
Радость

это ответ почему компилятор не хочет делать то, что задумал программист. подробности можно прочитать в любой книжке. просто если сейчас не разобраться с этим, то будущее очень туманно.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #8  
Старый 24.04.2015, 22:05
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Короче, вроде создал я критическую секцию эту, будь она неладна, через Initialize, а не Create))) В общем с потоком получилось у меня вот так:
Код:
procedure TMyThread.Execute;
  var
  HTML: string;
  Acc: integer;
begin;
for Acc := 0 to Accounts.Count-1 do
 begin
 if Terminated
 then break;
 ProgressPos:=Acc;
 Synchronize(ProgressBar);
 Login:=copy(Accounts[Acc], 1, pos(del, Accounts[Acc])-1);
 Password:=copy(Accounts[Acc], pos(del, Accounts[Acc])+1, MaxInt);
 EnterCriticalSection(CS);
 HTML:=Form2.IdHTTP1.Get('http://xxxxxx'+Login+'xxxxxx'+Password);
  if pos ('xxxxxx', HTML)<>0 then
  if Form2.sEdit3.Text<>'' then
  begin
   HTML:=Form2.IdHTTP1.Get('https://xxxxxx'+Form2.sEdit3.Text+'xxxxxx');
   LeaveCriticalSection(CS);
   if pos ('xxxxxx', HTML)<>0 then
    begin
     Synchronize(Bad);
    end
    else
    begin
     Synchronize(Good);
    end
  end
  else
  begin
     Synchronize(Good);
  end
else
begin
Synchronize(Bad);
end;
Synchronize(WriteFile);
end;
end;
вроде бы одинаковые результаты не выдаёт, но что-то мне сдаётся что быстрее оно вообще работать не стало, что один поток, что 100. Я так подозреваю, что причина именно в одном экземпляре IdHttp?

Последний раз редактировалось AlexBerg001, 25.04.2015 в 02:15.
Ответить с цитированием
  #9  
Старый 25.04.2015, 01:33
icheezy icheezy вне форума
Прохожий
 
Регистрация: 24.04.2015
Сообщения: 11
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Отправка сообщений одновременно всем

Очень сложно для меня
Ответить с цитированием
  #10  
Старый 25.04.2015, 02:11
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Ну или вот второй вариант без критической секции
Код:
procedure TMyThread.Execute;
  var
  HTML: string;
  Acc: integer;
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
begin;
 IdHTTP := TIdHTTP.Create;
 IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create;
 IdHTTP.HandleRedirects:=true;
 IdHTTP.IOHandler:=IdSSL;
for Acc := 0 to Accounts.Count-1 do
 begin
 if Terminated
 then break;
 ProgressPos:=Acc;
 Synchronize(ProgressBar);
 Login:=copy(Accounts[Acc], 1, pos(del, Accounts[Acc])-1);
 Password:=copy(Accounts[Acc], pos(del, Accounts[Acc])+1, MaxInt);
 HTML:=IdHTTP.Get('http://xxxxxx'+Login+'xxxxxx'+Password);
  if pos ('xxxxxx', HTML)<>0 then
  if Form2.sEdit3.Text<>'' then
  begin
   HTML:=IdHTTP.Get('https://xxxxxx'+Form2.sEdit3.Text+'xxxxxx');
  if pos ('xxxxxx', HTML)<>0 then
    begin
     Synchronize(Bad);
    end
    else
    begin
     Synchronize(Good);
    end
  end
  else
  begin
     Synchronize(Good);
  end
else
begin
Synchronize(Bad);
end;
Synchronize(WriteFile);
end;
IdHTTP.Free;
IdSSL.Free;
end;
Ну тут, вообще очень быстро, зато миллион одинаковых строк)))

Последний раз редактировалось AlexBerg001, 25.04.2015 в 12:09.
Ответить с цитированием
  #11  
Старый 25.04.2015, 10:06
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

В общем вопрос в том как сделать так, чтобы каждый новый поток брал следующую строку из Accounts
Ответить с цитированием
  #12  
Старый 25.04.2015, 17:20
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

если использовать асинхронные (не блокируемые) сокеты, то потоки вообще не нужны.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #13  
Старый 25.04.2015, 18:01
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Можно поподробнее немного? Что-то я не понял. Немного почитал про сокеты, но не так чтобы сильно понял. Понял только, что нужно как-то режим переключить, а как это можно сделать?

Последний раз редактировалось AlexBerg001, 25.04.2015 в 21:40.
Ответить с цитированием
  #14  
Старый 27.04.2015, 02:45
AlexBerg001 AlexBerg001 вне форума
Прохожий
 
Регистрация: 13.04.2015
Сообщения: 24
Версия Delphi: Delphi 2010
Репутация: 10
По умолчанию

Мне кто нибудь подскажет, как переделать проект так чтобы потоки не обрабатывали одинаковые строки в Accounts или я тут сам с собой переписываюсь???
Ответить с цитированием
  #15  
Старый 27.04.2015, 07:57
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

очевидно каждому потоку надо передавать свой набор исх. данных.
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
Ответ


Delphi Sources

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

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 15:25.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025