为什么线程不执行,还是执行?
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 成员中。
您等待线程完成的方式 运行 既不正确又低效。
我正在尝试为命令行界面创建一个多线程随机数生成器,为此我使用 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 成员中。
您等待线程完成的方式 运行 既不正确又低效。