Delphi中的多线程队列? [英] Multithread queue in delphi?

查看:555
本文介绍了Delphi中的多线程队列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的第二个问题,我对此有一些麻烦。<

This is my second question about this, im having some troubles with this >.<

我只想创建有限数量的线程(在在这种情况下,我需要10个线程),然后每个线程都会在列表中选择一个名称,并在我的网站中获取一些数据。

Well, I just want to create a limited number of threads (in this case, I want 10 threads), and then each thread will pick up a name in my list and get some data in my site.

我的系统运行良好,但是我的多线程系统仍然失败=(

My system works pretty well, but my multi thread system still fails =(

-

我尝试了LU RD发布的代码,但是主线程不等待线程完成队列,而是停止=(

I tried the code posted by LU RD, but the main thread don't wait the threads finish the queue, and just stops =(

代码:

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;

我的另一个问题:多线程Delphi

Im使用Delphi XE3。

Im using Delphi XE3.

推荐答案


  • 首先,如果要调用过程 DoSomeJob()并阻塞直到从主线程准备好,有一个警告。如果您的工作线程正在与主线程同步,则 aCounter.WaitFor TThread.Synchronize()

    • First, if you want to call the procedure DoSomeJob() and block until ready from the main thread, there is a caveat. If your worker threads are synchronizing with the main thread, there is a dead-lock situation with aCounter.WaitFor and TThread.Synchronize().
    • 我以为这是发生在您身上的事情,在这里猜测。

      I am assuming that this is what is happening to you, guessing here.

      有一种方法可以解决这个问题,正如我在此答案中所展示的。

      There is a way to handle that as I will show in this answer.


      • 第二,通常是工人线程应由线程池处理,以避免始终创建/销毁线程。将您的工作传递到线程池,以便所有内容在线程内运行并等待。这样可以避免阻塞主线程。
        我会留给你。一旦编写了该框架,线程将变得更加容易。如果这看起来很复杂,请尝试使用 OTL 线程框架。

      • Second, normally the worker threads should be handled by a thread pool, to avoid create/destroy threads all the time. Pass your job to the thread pool, so everything is run and waited for inside a thread. This avoids blocking the main thread. I will leave this up to you. Once that framework is written, threading will be easier. If this seems complex, try OTL threading framework instead.

      这里是一个示例,其中主线程可以等待 DoSomeJob()以安全的方式。
      创建了一个匿名线程来等待 aCounter 发出信号。
      本示例使用 TMemo TButton 。只需使用这些组件创建一个表单,然后将按钮 OnClick 事件连接到 ButtonClick 方法。

      Here is an example where the main thread can wait for DoSomeJob() in a safe manner. An anonymous thread is created to wait for the aCounter to signal. This example uses a TMemo and a TButton. Just create a form with these components and connect the button OnClick event to the ButtonClick method.

      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.  
      

      这篇关于Delphi中的多线程队列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆