2013-04-25 4 views
0

Это мой второй вопрос об этом, у меня есть некоторые проблемы с этим>. <Многопоточная очередь в delphi?

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

Моя система работает довольно хорошо, но моя Мультисистемная нить все еще не = (

-

Я попытался код, отправленный LU RD, но основной поток не ждать нитей закончить очереди, а просто останавливается = (

код:

uses 
Classes,SyncObjs,Generics.Collections; 

Type 
TMyConsumerItem = class(TThread) 
private 
FQueue : TThreadedQueue<TProc>; 
FSignal : TCountDownEvent; 
protected 
procedure Execute; override; 
public 
constructor Create(aQueue : TThreadedQueue<TProc>; aSignal : TCountdownEvent); 
end; 

constructor TMyConsumerItem.Create(aQueue: TThreadedQueue<TProc>; aSignal : TCountDownEvent); 
begin 
Inherited Create(false); 
Self.FreeOnTerminate := true; 
FQueue := aQueue; 
FSignal := aSignal; 
end; 

procedure TMyConsumerItem.Execute; 
var 
aProc : TProc; 
begin 
try 
repeat 
    FQueue.PopItem(aProc); 
    if not Assigned(aProc) then 
    break; // Drop this thread 
    aProc(); 
until Terminated; 
finally 
    FSignal.Signal; 
end; 
end; 

procedure DoSomeJob(myListItems : TStringList); 
const 
cThreadCount = 10; 
cMyQueueDepth = 100; 
var 
i : Integer; 
aQueue : TThreadedQueue<TProc>; 
aCounter : TCountDownEvent; 
function CaptureJob(const aString : string) : TProc; 
begin 
Result := 
    procedure 
    begin 
    // Do some job with aString 
    end; 
end; 
begin 
aQueue := TThreadedQueue<TProc>.Create(cMyQueueDepth); 
aCounter := TCountDownEvent.Create(cThreadCount); 
try 
for i := 1 to cThreadCount do 
    TMyConsumerItem.Create(aQueue,aCounter); 
for i := 0 to myListItems.Count-1 do begin 
    aQueue.PushItem(CaptureJob(myListItems[i])); 
end; 
finally 
for i := 1 to cThreadCount do 
    aQueue.PushItem(nil); 
aCounter.WaitFor; // Wait for threads to finish 
aCounter.Free; 
aQueue.Free; 
end; 
end; 

Мой другой вопрос: Multi Thread Delphi

Im используя Delphi XE3.

+0

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

+0

OmniThreadLibrary имеет как пулы потоков, так и неблокируемый многопоточный класс очереди –

+0

@LU RD. Проблема заключается в том, что основной поток просто нажимает nil до того, как потоки выполняют работу. Я действительно не знаю, почему = (очередь потоков .Man настолько сложна. 0. – Kirito94

ответ

5
  • Во-первых, если вы хотите вызвать процедуру DoSomeJob() и заблокировать до готовности к основной теме, есть оговорка. Если ваши рабочие потоки синхронизируются с основным потоком, существует ситуация с мертвой блокировкой с aCounter.WaitFor и TThread.Synchronize().

Я предполагаю, что это то, что происходит с вами, угадывая здесь.

Существует способ справиться с этим, как я покажу в этом ответе.

  • Во-вторых, обычно рабочие потоки должны обрабатываться пулом потоков, чтобы избежать создания/уничтожения потоков все время. Передайте свою работу в пул потоков, поэтому все выполняется и ждет внутри потока. Это позволяет избежать блокировки основного потока. Я оставлю это вам. После того, как эта структура будет написана, потоки будут проще. Если это кажется сложным, попробуйте OTL threading framework.

См. Здесь, где main thread может подождать DoSomeJob() безопасным способом. Анонимный поток создается, чтобы ждать сигнала aCounter. В этом примере используются TMemo и TButton. Просто создайте форму с этими компонентами и подключите кнопку OnClick к методу ButtonClick.

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
    System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Memo1: TMemo; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    procedure DoSomeJob(myListItems : TStringList); 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

uses 
    SyncObjs, Generics.Collections; 

{- Include TMyConsumerItem class here } 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    aList : TStringList; 
    i : Integer; 
begin 
    aList := TStringList.Create; 
    Screen.Cursor := crHourGlass; 
    try 
    for i := 1 to 20 do aList.Add(IntToStr(i)); 
    DoSomeJob(aList); 
    finally 
    aList.Free; 
    Screen.Cursor := crDefault; 
    end; 
end; 

procedure TForm1.DoSomeJob(myListItems: TStringList); 
const 
    cThreadCount = 10; 
    cMyQueueDepth = 100; 
var 
    i: Integer; 
    aQueue: TThreadedQueue<TProc>; 
    aCounter: TCountDownEvent; 

    function CaptureJob(const aString: string): TProc; 
    begin 
    Result := 
     procedure 
     var 
     i,j : Integer; 
     begin 
     // Do some job with aString 
     for i := 0 to 1000000 do 
      j := i; 
     // Report status to main thread 
     TThread.Synchronize(nil, 
      procedure 
      begin 
      Memo1.Lines.Add('Job with:'+aString+' done.'); 
      end 
     ); 

     end; 
    end; 
var 
    aThread : TThread; 
begin 
    aQueue := TThreadedQueue<TProc>.Create(cMyQueueDepth); 
    aCounter := TCountDownEvent.Create(cThreadCount); 
    try 
    for i := 1 to cThreadCount do 
     TMyConsumerItem.Create(aQueue, aCounter); 
    for i := 0 to myListItems.Count - 1 do 
    begin 
     aQueue.PushItem(CaptureJob(myListItems[i])); 
    end; 
    // Kill the worker threads 
    for i := 1 to cThreadCount do 
     aQueue.PushItem(nil); 
    finally 
    // Since the worker threads synchronizes with the main thread, 
    // we must wait for them in another thread. 
    aThread := TThread.CreateAnonymousThread(
     procedure 
     begin 
     aCounter.WaitFor; // Wait for threads to finish 
     aCounter.Free; 
     aQueue.Free; 
     end 
    ); 
    aThread.FreeOnTerminate := false; 
    aThread.Start; 
    aThread.WaitFor; // Safe to wait for the anonymous thread 
    aThread.Free; 
    end; 
end; 

end. 
+0

Я думаю, что теперь вы будете работать. Вы правы, мои рабочие потоки синхронизируются с основным потоком, когда мой веб-сервер будет в сети, я буду тестировать, вероятно, 7:00 вечера (GMT -3). Спасибо LU RD =) --Edit Забыл спросить, почему у CreateAnonymousThread есть var i? – Kirito94

+0

Вы можете игнорировать переменную i. Оставшийся я забыл удалить. Готово! –

+0

Не работает. Может быть, это одна из моих функций, которая вызывает проблемы? Когда я запускаю процесс, 10 рабочих потоков запускаются нормально, но что-то нарушает рабочие потоки, потому что они просто останавливаются = (. Я просмотрю весь свой код, я думаю, что проблема теперь в моем коде. В любом случае, спасибо LU RD. – Kirito94

Смежные вопросы