Создание многопоточного приложения [Delphi]

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Artist, 4 Aug 2010.

  1. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Вот написал простенький сортировщик почты на одном потоке.Как его реализовать в многопоточное приложения?
    Например:
    Чтоб можно было выбрать количество потоков...
    1 поток выбирает 1 строку и сортирует
    2 поток выбирает 2 строку и сортирует
    и так далее...
    Вот сама программа + исходный код ТУТ
    И еще вопрос: Terminate; в моем коде не работает, может надо создавать поток с другими параметрами?

    Code:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, Unit2, XPMan;
    
    type
      TForm1 = class(TForm)
        Memo1: TMemo;
        Memo2: TMemo;
        Memo3: TMemo;
        Memo4: TMemo;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Button1: TButton;
        XPManifest1: TXPManifest;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
      new:TNew;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    new:=TNew.Create(True);
    new.FreeOnTerminate:=true;
    new.Priority:=tpNormal;
    new.Resume;
    
    end;
    
    procedure TForm1.Button4Click(Sender: TObject);
    begin
    new.Terminate;
    end;
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
    new.Suspend;
    end;
    
    procedure TForm1.Button3Click(Sender: TObject);
    begin
    new.Resume;
    end;
    
    end.

    Code:
    unit Unit2;
    
    interface
    
    uses
      Classes;
    
    type
      TNew = class(TThread)
      private
        { Private declarations }
      protected
        procedure Execute; override;
      end;
    
    implementation
    
    uses
      Windows, Messages, SysUtils, Variants, Graphics, Controls, Forms,
      Dialogs, Unit1;
    
    procedure TNew.Execute;
    var
    i:integer;
    s:string;
    begin
    for i:=0 to Form1.Memo1.Lines.Count-1 do
    begin
    if pos('mail.ru',Form1.Memo1.Lines[i])<>0 then
    begin
    s:=copy(Form1.Memo1.Lines[i],1,length(Form1.Memo1.Lines[i]));
    Form1.Memo2.Lines.Add(s);
    end;
    if pos('rambler.ru',Form1.Memo1.Lines[i])<>0 then
    begin
    s:=copy(Form1.Memo1.Lines[i],1,length(Form1.Memo1.Lines[i]));
    Form1.Memo3.Lines.Add(s);
    end;
    if pos('yandex.ru',Form1.Memo1.Lines[i])<>0 then
    begin
    s:=copy(Form1.Memo1.Lines[i],1,length(Form1.Memo1.Lines[i]));
    Form1.Memo4.Lines.Add(s);
    end;
    end;
    end;
    
    end.
    
     
    #1 Artist, 4 Aug 2010
    Last edited: 4 Aug 2010
  2. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    1) Зачем это делать многопоточным?
    2) Terminate не завершает поток, а меняет значение переменной Terminated на true;
     
  3. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    На примере этой программы хочу узнать как создать многопоточное приложение.
    При работы с большим количеством почты многопоточность уменьшит затраченное время на сортировку.
    Прочитал в таблице что " Terminate - Метод Вызывается для завершения потока."
    Если это не так то тогда как полностью завершить поток?
     
  4. fenixelite

    fenixelite Banned

    Joined:
    7 Feb 2010
    Messages:
    294
    Likes Received:
    56
    Reputations:
    6
    Делаешь в потоке цикл while (Terminated = false) do и все. И поток будет работать пока terminated не вернет true
     
  5. CraftR14

    CraftR14 New Member

    Joined:
    23 May 2010
    Messages:
    10
    Likes Received:
    3
    Reputations:
    0
    https://forum.antichat.ru/thread221388.html
    делфи. многопоточность через gsvthread-ы
     
  6. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    1 поток выбирает 1 строку и сортирует
    2 поток выбирает 2 строку и сортирует

    заюзай такой алгоритм
    пусть строки будут глобальным массивом
    и количество потоков тоже глобальной переменной (глобальной - видной всем потокам)
    через переменную ты передаешь функции потока стартовый номер строки с которой считать а в потоке циклом
    i=start; while (Terminated != false) { ... i=i+count_thread; if(i>count_array) i=start; }
    что-то типа...
     
    _________________________
  7. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Code:
    unit Unit2;
    
    interface
    
    uses
      Classes, SysUtils;
    
    type
      TMailHost = (mhNone, mhMail, mhRambler, mhYandex);
      TNew = class(TThread)
      private
        { Private declarations }
        fMail: string;
        fMailHost: TMailHost;
        procedure GetNextMail;
        procedure SaveResult;
      protected
        procedure Execute; override;
      end;
    
    implementation
    uses
      Unit1;
    
    { TNew }
    
    procedure TNew.Execute;
    begin
      while not Terminated do begin
        fMailHost:=mhNone;
        Synchronize(GetNextMail);
        if pos('mail.ru', fMail)>0 then
          fmailHost:=mhMail
        else if pos('rambler.ru', fMail)>0 then
          fMailHost:=mhRambler
        else if pos('yandex.ru', fMail)>0 then
          fMailHost:=mhYandex;
        Synchronize(SaveResult);
      end;
    end;
    
    procedure TNew.GetNextMail;
    begin
      fMail:='';
      if Form1.Memo1.Lines.Count>0 then begin
        fMail:=LowerCase(Form1.Memo1.Lines[0]);
        Form1.Memo1.Lines.Delete(0);
      end;
    end;
    
    procedure TNew.SaveResult;
    begin
      case fMailHost of
        mhNone: ;
        mhMail: Form1.Memo2.Lines.Add(fMail);
        mhRambler: Form1.Memo3.Lines.Add(fMail);
        mhYandex: Form1.Memo4.Lines.Add(fMail);
      end;
    end;
    
    end.
    
    Это код для потока. Как создать и убить N-ное количество потоков тебе уже рассказали
     
  8. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Скорее наоборот, увеличит время сортировки.
     
  9. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Согласен. Но в качестве опыта подойдет.
    Увеличит из-за накладных расходов на синхронизацию. И чем больше будет потоков, тем медленнее будет работать, такой вот парадокс.
     
    #9 Redeemer, 4 Aug 2010
    Last edited: 4 Aug 2010
  10. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Всем спасибо!
    Буду разбираться...
     
  11. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    дополнение:
    на однопроцессорных системах увеличит на системах с количеством процессоров > 1 можно добится лучших результатов чем с одним потоком каждый поток на своем процессоре реальное одновременное выполнение а не фиктивное как на одном процессоре
     
  12. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Я прикидывал от нефиг делать - 2 потока на ядро дает прирост примерно 12%, три потока на ядро всего 1%, выше уже в минус
     
  13. greki_hoy

    greki_hoy Member

    Joined:
    4 Mar 2010
    Messages:
    326
    Likes Received:
    57
    Reputations:
    41
    конечно тут же очень важно чем занимаются потоки если например числодробильню разделить на два потока на однопроцессорной машине то только снизиш производительность а если например сетевой ввод вывод на той же однопроцессорной машине то можно весьма неплохо поднять эту самую производительность если прикрутить больше одного потока
     
  14. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Разобрался и все получилось, а теперь вопрос при 2 и более потоках TidHttp надо синхронизировать или поставить в критическую секцию?
     
  15. M_script

    M_script Members of Antichat

    Joined:
    4 Nov 2004
    Messages:
    2,581
    Likes Received:
    1,317
    Reputations:
    1,557
    Нужно создавать объект TIdHTTP в потоке. Если все хттп-запросы будут в крит.секции, то какой смысл в многопоточности?
     
  16. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Спасибо все помогло, но я заметил что TidHttp только на 30 потоков хватает...


    Теперь вопрос такой, как сделать паузу/продолжить всех потоков и завершение?
     
  17. Redeemer

    Redeemer Member

    Joined:
    3 Jul 2010
    Messages:
    203
    Likes Received:
    24
    Reputations:
    1
    Как это? Поясни

    У потока есть методы Suspend и Resume - первый усыпляет поток, второй будит
     
  18. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Запускаю 100 потоков(Выполнение простого гет запроса), а в снифере всего 32 отображается...
    Про Suspend и Resume я уже понял.
    var
    i:integer;
    begin
    for i:=1 to SpinEdit1.Value do
    thr.Suspend;
    end;
    И также Resume

    А вот проблемма, как их закончить всех?.
     
  19. fenixelite

    fenixelite Banned

    Joined:
    7 Feb 2010
    Messages:
    294
    Likes Received:
    56
    Reputations:
    6
    Ограничение в системе на кол-во соединений скорее всего. IdHTTP тут не причем
     
  20. Artist

    Artist Member

    Joined:
    10 Jul 2010
    Messages:
    89
    Likes Received:
    5
    Reputations:
    0
    Да ты оказался прав снифер не отображал все запросы(После перезапуска все нормально было)

    Пробывал закончить все потоки так, но не выходит!

    Code:
    procedure tnew.Execute;
    begin
    while not Terminated do 
    begin
    {Мой код}
    end;
    end;
    
    На кнопку поставил и жму.



    Code:
     var
      thr: array [1..100] of TNew;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
    i:integer;
    begin
      for i:=1 to SpinEdit1.Value do
      begin
      thr[i].Terminate;
    end;
    end;
    
    Хотя если сделать так то поток не выполняется
    while (Terminated = true) do
    begin
    end;
    Значить Terminate не чего не возвращает и Terminated не меняется с False на True.

    Как же их закончить?
     
    #20 Artist, 5 Aug 2010
    Last edited: 5 Aug 2010