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

发布于 2025-02-01 11:49:05 字数 5727 浏览 4 评论 0原文

我正在尝试为命令行接口做一个多线程随机数生成器,为此,我使用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.

I am trying to make a multithreaded random number generator for the command line interface, and for that I use TThreads to use multiple cpu cores to make random numbers. My program works till I try to start a thread, as it seemingly starts but, as far as I can tell, doesn't execute its code, because then my loop in line 196 should end, but it doesn't.


{$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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

执笔绘流年 2025-02-08 11:49:05

线程有很多问题:

  • 线程[i] .greate(true);是创建线程对象的错误方法。您需要使用线程[i]:= tmythread.create(true);而不是。

  • 您正在使用createSuspended = true创建每个线程,但是您在任何线程上不调用start> start()恢复它们,以便它们实际运行。 /p>

  • 您的execute()方法正在调用synchronize()作为其非常第一语句。但是您的项目是一个没有消息循环的控制台应用程序,该应用程序 请求,因此所有线程都会立即死锁。至少,您的主线程需要调用class.checksynchronize()在工作线程运行时定期。

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

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

There are a number of problems with your threads:

  • threads[i].create(true); is the wrong way to create the thread objects. You need to use threads[i] := TMyThread.Create(true); instead.

  • you are creating each thread with CreateSuspended=True, but you don't call Start() on any of the threads to resume them so they actually run.

  • your Execute() method is calling Synchronize() as its very 1st statement. But your project is a console app without a message loop that processes Synchronize() requests, so all of your threads will deadlock immediately. At the very least, your main thread needs to call Classes.CheckSynchronize() periodically while the worker threads are running.

  • your threads are sharing and modifying global variables without any synchronization between them. Any variables that don't need to be shared globally (like each thread's array index) should be passed to the thread's constructor and stored in class members instead.

  • the way you are waiting for the threads to finish running is both incorrect and inefficient.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文