Reputation: 11435
if I've got a
While not terminated do
begin
doStuff;
end
loop in the execute method of a Delphi XE2 thread, and I want to not make it bogart all my flops.
What should I call,
in Delphi 7, it was easy, I'd call Sleep(X) where X was inversely proportional to how interesting I thought the thread was.
But now, I've got
SpinWait(X);
Which calls YieldProcessor X number of times
and
Yield;
which calls the windows function "SwitchToThread".
Should I use any of these or should I just set the priority of the thread?
Upvotes: 3
Views: 3117
Reputation: 24847
Threadpool example:
unit ThreadPool;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, contnrs, syncobjs;
type
TpooledTask=class(TObject)
private
FonComplete:TNotifyEvent;
protected
Fparam:TObject;
procedure execute; virtual; abstract;
public
constructor create(onComplete:TNotifyEvent;param:TObject);
end;
TThreadPool=class(TObjectQueue)
private
access:TcriticalSection;
taskCounter:THandle;
threadCount:integer;
public
constructor create(initThreads:integer);
procedure addTask(aTask:TpooledTask);
end;
TpoolThread=class(Tthread)
private
FmyPool:TThreadPool;
protected
procedure Execute; override;
public
constructor create(pool:TThreadPool);
end;
implementation
{ TpooledTask }
constructor TpooledTask.create(onComplete: TNotifyEvent; param: TObject);
begin
FonComplete:=onComplete;
Fparam:=param;
end;
{ TThreadPool }
procedure TThreadPool.addTask(aTask: TpooledTask);
begin
access.acquire;
try
push(aTask);
finally
access.release;
end;
releaseSemaphore(taskCounter,1,nil); // release one unit to semaphore
end;
constructor TThreadPool.create(initThreads: integer);
begin
inherited create;
access:=TcriticalSection.create;
taskCounter:=createSemaphore(nil,0,maxInt,'');
while(threadCount<initThreads) do
begin
TpoolThread.create(self);
inc(threadCount);
end;
end;
{ TpoolThread }
constructor TpoolThread.create(pool: TThreadPool);
begin
inherited create(true);
FmyPool:=pool;
FreeOnTerminate:=true;
resume;
end;
procedure TpoolThread.execute;
var thisTask:TpooledTask;
begin
while (WAIT_OBJECT_0=waitForSingleObject(FmyPool.taskCounter,INFINITE)) do
begin
FmyPool.access.acquire;
try
thisTask:=TpooledTask(FmyPool.pop);
finally
FmyPool.access.release;
end;
thisTask.execute;
if assigned(thisTask.FonComplete) then thisTask.FonComplete(thisTask);
end;
end;
end.
Upvotes: 1
Reputation: 163247
SpinWait
wastes time without giving up the processor. It's like Sleep
, but without yielding control to any other threads during the delay. If you don't have multiple cores, then it's a total waste because no other thread can do anything while you're spinning. As far as I can tell, Yield
is analogous to Sleep(0)
, except that if there is no other thread ready to run, then the calling thread just continues immediately.
Neither of those sounds like what you want if you know that your thread really has nothing else to do.
The best solution would be to find or establish some waitable object (like a semaphore, event, or process handle) that you could wait to become signaled. Then you wouldn't have to bother waking up at all, just so you can poll your status and go to sleep again.
Upvotes: 7