Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 在Delphi中使用线程队列时,如何确保释放线程?_Multithreading_Delphi - Fatal编程技术网

Multithreading 在Delphi中使用线程队列时,如何确保释放线程?

Multithreading 在Delphi中使用线程队列时,如何确保释放线程?,multithreading,delphi,Multithreading,Delphi,我再次,希望有更具体的线程问题 我注意到,如果我在这里运行Chris Rolliston提供的优秀演示: 打开FastMM以报告内存泄漏时,线程本身也会泄漏 这对于一个小的演示来说并没有问题,但对于我的应用程序来说,使用线程的迭代次数达到了数万次,它会耗尽内存来运行我那不起眼的32位应用程序。(我无法编译64位,因为我使用的是仅32位的串扰) 当与线程队列一起使用时,如何确保线程被释放 新增代码 program SimpleThreadQueueConsole; {$APPTYPE CONS

我再次,希望有更具体的线程问题

我注意到,如果我在这里运行Chris Rolliston提供的优秀演示:

打开FastMM以报告内存泄漏时,线程本身也会泄漏

这对于一个小的演示来说并没有问题,但对于我的应用程序来说,使用线程的迭代次数达到了数万次,它会耗尽内存来运行我那不起眼的32位应用程序。(我无法编译64位,因为我使用的是仅32位的串扰)

当与线程队列一起使用时,如何确保线程被释放

新增代码

program SimpleThreadQueueConsole;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  FastMM4,
  System.SysUtils,
  System.SyncObjs,
  uPrimeThread in 'uPrimeThread.pas',
  uPrimeThreadRunner in 'uPrimeThreadRunner.pas';

var
  PR: TPrimeThreadRunner;

begin
  Randomize;
  ReportMemoryLeaksOnShutdown := True;
  PR := TPrimeThreadRunner.Create;
  try
    PR.DoIt;
  finally
    PR.Free;
  end;

end.
uPrimeThread.pas

    unit uPrimeThread;

    interface

    uses
          System.Classes
        , Generics.Collections
        ;

    type

      TPrimeThread = class(TThread)
      private
        FOutQueue: TThreadedQueue<string>;
        FInQueue: TThreadedQueue<string>;
        function IsPrime(const NumberToCheck: integer): boolean;
      public
        constructor Create(aCreateSuspended: Boolean; aInQueue:  TThreadedQueue<string>; aOutQueue:  TThreadedQueue<string>);
        procedure Execute; override;
      end;

    implementation

    uses
          System.SysUtils
        , System.SyncObjs
        ;

    const
      MaxPrime = 999;


    { TPrimeThread }

    constructor TPrimeThread.Create(aCreateSuspended: Boolean; aInQueue, aOutQueue: TThreadedQueue<string>);
    begin
      inherited Create(aCreateSuspended);
      FOutQueue := aOutQueue;
      FInQueue := aInQueue;
      FreeOnTerminate := True;
    end;

    procedure TPrimeThread.Execute;
    var
      S: string;
      ThreadID: TThreadID;
      NumberToCheck: integer;
    begin

        ThreadID := TThread.CurrentThread.ThreadID;
        FOutQueue.PushItem(Format('Thread %d started...', [ThreadID]));

        while (FInQueue.PopItem(S) = wrSignaled) do
        begin
          NumberToCheck := Random(MaxPrime);
          if IsPrime(NumberToCheck) then
          begin
            FOutQueue.PushItem(Format('%s using thread %d: %d is prime', [S, ThreadID, NumberToCheck]));
          end else
          begin
            FOutQueue.PushItem(Format('%s using thread %d: %d is NOT prime', [S, ThreadID, NumberToCheck]));
          end;
        end;
    end;

    function TPrimeThread.IsPrime(const NumberToCheck: Integer): boolean;
    // This is really bad on purpose to make the threads work a little harder
    var
      i: integer;
    begin
      Result := True;
      if NumberToCheck in [0, 1] then
      begin
        Result := False;
        Exit;
      end;

      for i := 2 to NumberToCheck - 1 do
      begin
        if NumberToCheck mod i = 0 then
        begin
          Result := False;
          Exit;
        end;
      end;
    end;

    end.
unituprimethread;
接口
使用
系统、类
,泛型。集合
;
类型
TPrimeThread=class(TThread)
私有的
FOutQueue:TThreadedQueue;
FInQueue:TThreadedQueue;
函数IsPrime(常量NumberToCheck:integer):布尔;
公众的
构造函数创建(aCreateSuspended:Boolean;aInQueue:TThreadedQueue;aOutQueue:TThreadedQueue);
程序执行;推翻
结束;
实施
使用
System.SysUtils
,System.SyncObjs
;
常数
MaxPrime=999;
{TPrimeThread}
构造函数TPrimeThread.Create(aCreateSuspended:Boolean;aInQueue,aOutQueue:TThreadedQueue);
开始
继承的创建(aCreateSuspended);
FOutQueue:=aOutQueue;
FInQueue:=aInQueue;
FreeOnTerminate:=真;
结束;
过程TPrimeThread.Execute;
变量
S:字符串;
ThreadID:TThreadID;
NumberToCheck:整数;
开始
ThreadID:=TThread.CurrentThread.ThreadID;
PushItem(格式('Thread%d started…',[ThreadID]);
而(FInQueue.PopItem)=wrSignaled)do
开始
NumberToCheck:=随机(MaxPrime);
如果是iPrime(数字检查),则
开始
PushItem(格式('%s使用线程%d:%d为prime',[s,线程ID,NumberToCheck]);
结束其他
开始
PushItem(格式(“%s”使用线程%d:%d不是prime,[s,ThreadID,NumberToCheck]);
结束;
结束;
结束;
函数TPrimeThread.IsPrime(常量NumberToCheck:Integer):布尔;
//这是非常糟糕的故意使线程工作更努力
变量
i:整数;
开始
结果:=真;
如果Number签入[0,1],则
开始
结果:=假;
出口
结束;
对于i:=2到数字检查-1 do
开始
如果NumberToCheck mod i=0,则
开始
结果:=假;
出口
结束;
结束;
结束;
结束。
uPrimeThreadRunner.pas

unit uPrimeThreadRunner;

interface

uses
      System.SyncObjs

    , Generics.Collections
    , System.SysUtils
    , uPrimeThread
    ;

const
  ThreadCount = 4;

type
  TPrimeThreadRunner = class
  private
    FTotalThreads: TCountdownEvent;
    FInQueue, FOutQueue: TThreadedQueue<string>;
    FCurrentEntry: integer;
    procedure DrainTheQueue;
    procedure AddEntry;
  public
    ThreadArray: array[1..ThreadCount] of TPrimeThread;
    procedure DoIt;
  end;

implementation

const
  NumberOfEntries = 10;

procedure TPrimeThreadRunner.DrainTheQueue;
var
  S: string;
begin
  while FOutQueue.PopItem(S) = wrSignaled do
    WriteLn(S);
end;

procedure TPrimeThreadRunner.AddEntry;
var
  S: string;
begin
  Inc(FCurrentEntry);
  S := Format('Entry %d:', [FCurrentEntry]) ;
  FInQueue.PushItem(S);
end;


procedure TPrimeThreadRunner.DoIt;
var
  i: integer;
begin
  FCurrentEntry := 0;

  FTotalThreads := TCountdownEvent.Create(1);
  FInQueue := TThreadedQueue<string>.Create(10, 1000, 1000);
  FOutQueue := TThreadedQueue<string>.Create(10, 1000, 1000);
  for i := 1 to ThreadCount do
  begin
    FTotalThreads.AddCount;
    try
      ThreadArray[i] := TPrimeThread.Create(True, FInQueue, FOutQueue);
      ThreadArray[i].Start;
    finally
      FTotalThreads.Signal;
    end;
  end;


  for I := 1 to NumberOfEntries do
  begin
    AddEntry;
  end;
  DrainTheQueue;

  FTotalThreads.Signal;
  FTotalThreads.WaitFor;
  FTotalThreads.Free;




  FInQueue.Free;
  FOutQueue.Free;

  Readln;
end;

end.
unitupriturerunner;
接口
使用
System.SyncObjs
,泛型。集合
,System.SysUtils
,向上螺纹
;
常数
线程数=4;
类型
tpromethreadrunner=class
私有的
FTotalThreads:TCountdownEvent;
FInQueue,FOutQueue:TThreadedQueue;
FCurrenentry:整数;
程序队列;
程序补遗;
公众的
ThreadArray:Tprimeread的数组[1..ThreadCount];
程序DoIt;
结束;
实施
常数
NumberOfEntries=10;
程序TPrimeThreadRunner.DrainTheQueue;
变量
S:字符串;
开始
而FOutQueue.PopItem=wrSignaled do
书面文件(S);;
结束;
程序TPrimeThreadRunner.AddEntry;
变量
S:字符串;
开始
公司(FCurrenentry);
S:=格式('条目%d:',[fcurrenentry]);
FInQueue.PushItem;
结束;
程序TPrimeThreadRunner.DoIt;
变量
i:整数;
开始
FCurrenentry:=0;
FTotalThreads:=TCountdownEvent.Create(1);
FInQueue:=TThreadedQueue.Create(10,1000,1000);
FOutQueue:=TThreadedQueue.Create(10,1000,1000);
对于i:=1到ThreadCount do
开始
FTotalThreads.AddCount;
尝试
ThreadArray[i]:=TPrimeThread.Create(True、FInQueue、FOutQueue);
ThreadArray[i].Start;
最后
FTotalThreads.信号;
结束;
结束;
对于I:=1到NumberOfEntries do
开始
补遗;
结束;
排龙;
FTotalThreads.信号;
FTotalThreads.WaitFor;
免费;
FInQueue.Free;
免费的;
Readln;
结束;
结束。

您的代码中有一个错误,我可以在XE3和XE6中复制它

关键错误如下:

for I := 1 to NumberOfEntries do
  begin
    AddEntry;
  end;
DrainTheQueue;  // <-- All threads may not be ready when this call finish

FTotalThreads.Signal;  // This makes nothing
FTotalThreads.WaitFor; // This makes nothing
FTotalThreads.Free;    // This makes nothing

FInQueue.Free;         // You may now free a queue in operation
FOutQueue.Free;        // You may now free a queue in operation
并更改PrimeThread。执行如下操作:

procedure TPrimeThread.Execute;
var
  S: string;
  ThreadID: TThreadID;
  NumberToCheck: integer;
begin

  ThreadID := TThread.CurrentThread.ThreadID;
  FOutQueue.PushItem(Format('Thread %d started...', [ThreadID]));
  try
    while NOT Terminated do
    begin
      if (FInQueue.PopItem(S) = wrSignaled) then
      begin
        if (S = '') then  // Stop executing 
          Exit;
        NumberToCheck := Random(MaxPrime);
        if IsPrime(NumberToCheck) then
        begin
          FOutQueue.PushItem(Format('%s using thread %d: %d is prime', [S, ThreadID, NumberToCheck]));
        end else
        begin
          FOutQueue.PushItem(Format('%s using thread %d: %d is NOT prime', [S, ThreadID, NumberToCheck]));
        end;
      end;
    end;
  finally
    FOutQueue.PushItem(Format('Thread %d ended ...', [ThreadID]));
  end;
end;
您还应该将
FTotalThreads
对象传递给工作线程,并让它们在完成执行时发出信号。
draintequeue
必须在
FTotalThreads.Waitfor

完成后释放线程。使用线程队列?到底是怎么回事?生产者/消费者?向使用者发送终止作业。完成后释放它。我使用的线程队列与上面链接的演示完全相同。事实上,就像现在一样,它会泄漏线程。如果我在通话结束后拨打免费电话,则应用程序会锁定呼叫免费。非网站链接。为什么代码不能在这里?必要时简化。通常,您会向队列发出终止的信号,然后所有消费者都会通过退出来响应该信号。等待他们全部收到信号。也许是通过破坏它们。是的,我猜线程中的循环不会检查线程是否被终止。除非您显式退出循环或强制终止线程(这是不建议的),否则该循环将一直持续下去。示例代码中的匿名工作线程会吐出状态消息-您是否看到
线程%d正在终止
消息?默认情况下,匿名线程是
FreeOnTerminate
线程。如果他们没有被释放,那是因为他们还没有完成工作。如果是这样的话,那么这个问题应该是:为什么我的工作线程被卡住了?是的!非常感谢你。这解决了我的问题
procedure TPrimeThread.Execute;
var
  S: string;
  ThreadID: TThreadID;
  NumberToCheck: integer;
begin

  ThreadID := TThread.CurrentThread.ThreadID;
  FOutQueue.PushItem(Format('Thread %d started...', [ThreadID]));
  try
    while NOT Terminated do
    begin
      if (FInQueue.PopItem(S) = wrSignaled) then
      begin
        if (S = '') then  // Stop executing 
          Exit;
        NumberToCheck := Random(MaxPrime);
        if IsPrime(NumberToCheck) then
        begin
          FOutQueue.PushItem(Format('%s using thread %d: %d is prime', [S, ThreadID, NumberToCheck]));
        end else
        begin
          FOutQueue.PushItem(Format('%s using thread %d: %d is NOT prime', [S, ThreadID, NumberToCheck]));
        end;
      end;
    end;
  finally
    FOutQueue.PushItem(Format('Thread %d ended ...', [ThreadID]));
  end;
end;