为什么线程不执行,还是执行?

Why doesn't the thread execute, or does it execute?

我正在尝试为命令行界面创建一个多线程随机数生成器,为此我使用 TThreads 来使用多个 cpu 内核来生成随机数。我的程序一直运行到我尝试启动一个线程为止,因为它看似启动了,但据我所知,它并没有执行它的代码,因为那时我在第 196 行的循环应该结束,但它没有。


{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes,
  sysutils,
  math;

type

  TMyThread = class(TThread)
  private
    procedure ShowStatus;
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: boolean);
  end;

var
  nums, temp1: int64;
  f: tfilestream;
  split_char: char;
  commands: array[0..2] of int64;
  writing: boolean = false;
  done: array of boolean;

constructor TMyThread.Create(CreateSuspended: boolean);
begin
  FreeOnTerminate := True;
  inherited Create(CreateSuspended);
end;

procedure TMyThread.ShowStatus;
begin
  done[temp1]:= false;
end;

procedure TMyThread.Execute;
var
  s, temp: string;
  i: uint64;
begin
  Synchronize(@Showstatus);
  i:= temp1;
  s:= '';
  while not nums < 0 do
  begin
    writeln('test.................................');
    dec(nums);
    temp:= inttostr(randomrange(commands[1], commands[2])) +  split_char;
    if high(s) + high(temp) > 4096 then
    begin
      if not writing then
      begin
        writing:= true;
        f.Write(s[1], high(s));
        s:= temp;
        writing:= false;
      end;
    end
    else
     s:= s + temp;
  end;
  done[i]:= true;
end;

var
  i, timestamp, timestamp2: uint64;
  temp, cores: int64;
  f_temp, temp_s: string;
  close, time, written, writeable, file_specified, numbers_specified, range_specified, split_char_specified: boolean;
  is_finished: boolean = false;
  threads: array of TMyThread;

label
  jump;

begin
  timestamp:= gettickcount64;
  time:= false;
  writeable:= false;
  written:= false;
  file_specified:= false;
  numbers_specified:= false;
  range_specified:= false;
  split_char_specified:= false;
  cores:= 0;
  for i:= 1 to paramcount() do
  try
      case paramstr(i) of
      '/f', '/file': begin
                       file_specified:= true;
                       f_temp:= paramstr(i + 1).split('"')[0];
                      if fileexists(f_temp) then
                        deletefile(f_temp);
                      f:= tfilestream.create(f_temp, fmcreate);
                      writeable:= true;
                    end;
      '/n', '/numbers': begin
                         numbers_specified:= true;
                         commands[0]:= strtoint(paramstr(i + 1)) - 1;
                       end;
      '/r', '/range': begin
                        range_specified:= true;
                        commands[1]:= strtoint((paramstr(i + 1).split(';'))[0]);
                        commands[2]:= strtoint((paramstr(i + 1).split(';'))[1]) + 1;
                      end;
      '/s', '/split', 'splitchar': begin
                                     split_char_specified:= true;
                                     split_char:=paramstr(i + 1)[1];
                                   end;
      '/t', '/time': time:= true;
      '/tr', '/truerand': randomize;
      '/c', '/cores': cores:= strtoint(paramstr(i + 1));
      end;
    except
      if not writeable then
      begin
        write('cannot write to file');
        written:= true;
      end;
      close:= true;
    end;
  if not file_specified then
      begin
        write('file not specified');
        written:= true;
        close:= true;
      end;
  if numbers_specified then
      begin
        if commands[0] < 1 then
        begin
          if written then
            write(#13);
          write('cannot generate <1 numbers');
          written:= true;
          close:= true;
        end;
      end
      else
      begin
        if written then
          write(#13);
        write('amount of numbers not specified');
        written:= true;
        close:= true;
      end;
      if not range_specified then
      begin
        if written then
          write(#13);
        write('range not specified');
        written:= true;
        close:= true;
      end
      else
        if commands[1] = commands[2] then
        begin
          temp:= commands[1];
          commands[2]:= commands[1];
          commands[2]:= temp;
        end;
      if not split_char_specified then
      begin
        if written then
          write(#13);
        write('split-char not specified');
        close:= true;
      end;
  if close then
    halt;
  try
    if (cores = 0) or (cores > getcpucount) then
      cores:= getcpucount;
    setlength(threads, cores);
    setlength(done, cores);
    for i:= low(threads) to high(threads) do
      threads[i]:= default(Tmythread);
    nums:= commands[0];
    writeln(inttostr(length(threads)));
    writeln('test0');
    writeln('threadcount: ' + inttostr(length(threads)));
    for i:= low(threads) to high(threads) do
    begin
      writeln('test?');
      threads[i].create(true);
      writeln('thread ' + inttostr(i) + ' initialized');
      temp1:= i;
      done[temp1]:= true;
      while done[temp1] = true do
      begin
        writeln('waiting for thread to start');
      end;
    end;
    writeln('test1');
    while not is_finished do
    begin
      i:= 0;
      jump:
      if not done[i] then
      goto jump;
      inc(i);
      if i = high(done) then
      is_finished:= true;
    end;
    temp_s:= inttostr(randomrange(commands[1], commands[2])) +  split_char;
    f.Write(temp_s[1], high(temp_s));
  except
    on e: exception do
    begin
      write(#13 + e.message);
      deletefile(paramstr(i));
      write('ERROR! Program will exit');
      exit;
    end;
  end;
  f.free;
  if time then
  begin
    if written then
      write(#13);
    write(floattostr((gettickcount64 - timestamp) / 1000) + ' seconds to execute');
  end;
end.

您的线程存在一些问题:

  • threads[i].create(true); 是创建线程对象的错误方法。您需要改用 threads[i] := TMyThread.Create(true);

  • 您正在使用 CreateSuspended=True 创建每个线程,但您没有在任何线程上调用 Start() 来恢复它们,因此它们实际上 运行。

  • 您的 Execute() 方法将调用 Synchronize() 作为其第一个语句。但是您的项目是一个控制台应用程序,没有处理 Synchronize() 请求的消息循环,因此您的所有线程都会立即死锁。至少,您的主线程需要在工作线程处于 运行ning 时定期调用 Classes.CheckSynchronize()

  • 您的线程正在共享和修改全局变量,但它们之间没有任何同步。任何不需要全局共享的变量(如每个线程的数组索引)都应传递给线程的构造函数并存储在 class 成员中。

  • 您等待线程完成的方式 运行 既不正确又低效。