Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Dynamically adding/removing threads in a pool, and waiting for busy ones? 2

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
I'm building a database thread pool, the pool has a property for thread count. By default this is 0 so there's no threads until this is set. The property reads the list count directly, so I don't store anything like "FThreadCount: Integer". So, the property setter needs to be responsible for adding/removing threads as necessary.

The adding threads part is easy, but removing them becomes tricky because I cannot kill a thread which is busy. So, when this needs to remove threads, it goes into a loop with a timeout and checks each thread's busy status. For each thread it finds not busy, it removes it, repeatedly until the count is down to the desired value.

My problem is I'm afraid to even try this, and before I try to run it (which I'm far from being able to run anyway), is this a good plan?

Code:
procedure TDBThreadPool.SetThreadCount(const Value: Integer);
const
  WAIT_TIMEOUT = 10; //Seconds to wait for available threads
var
  L: TList; //Locked thread list
  T: TDBThread; //Current thread
  D: Integer; //Difference in count
  X, Y: Integer; //Iterators
begin
  L:= LockThreads; //Acquire a locked list of threads
  try
    if (Value > L.Count) then begin
      //Add new threads
      D:= Value - L.Count;
      for X := 1 to D do begin
        T:= TDBThread.Create(Self);
        L.Add(T);
      end;
    end else
    if (Value < L.Count) then begin
      //Remove threads
      //Wait for their current processes, if any
      D:= L.Count - Value;
      for X := 1 to WAIT_TIMEOUT * 10 do begin
        for Y := L.Count - 1 downto 0 do begin
          T:= TDBThread(L[Y]);
          if not T.Busy then begin //"Busy" is true when thread is processing something
            T.Free;
          end;
          if L.Count = Value then Break;
        end;
        if L.Count = Value then Break;
        Sleep(100); (Sleep for 1/10 of a second
      end;
    end;
  finally
    UnlockThreads;
  end;
end;


JD Solutions
 
This is an interesting question, and one I've pursued myself in another way (scalable multi-processing for quicksort). I got it working well to start, but couldn't figure out how to schedule and restart my threads in order to keep them busy throughout the whole sort. I really have no time to look back into it any further at the moment, but just will say that I hope you find your answer, as I would like to know the answer to this too.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Please bear in mind that as mentioned, I have not even tried to run (or even compile) this yet, and yes there are problems such as I'm not removing the free'd thread from the list... It's the concept that I'm aiming for though.

JD Solutions
 
It could be as simple as "feeding the thread a poison" as someone told me once in the past, but that would require unmanaged threads, I need to carefully manage the existence of each one, up until its time of destruction. The way I'm moving, I can't depend on feeding it a poison command and hoping that it terminates its self in a decent amount of time. If all the threads are busy with a huge process, I'd like to know about it. If the timeout expires, and there's more threads remaining than desired, shall it raise an exception? If I don't implement the timeout, what if a thread never stops? I might have to go back to the poison method.

JD Solutions
 
@Jerry,

don't use sleep to wait for your threads to finish, use events:

Code:
//public var in thread:
FEvent : THandle; // or name it Busy if you want :)

//at thread construction:

FEvent := TEvent.Create(nil, False, True, nil);

// at the end of thread execute method:

SetEvent(FEvent);


//all you have to do now is wait for the event:

WaitForSingleObject(FEvent, 0 (or a Timeout in milliseconds)

//this way you don't need to guess when the thread has finished it's work

when working this way it's important to set FreeOnTerminate to False or else the thread may be gone when the main threads want to check the event (and crashes)

-----------------------------------------------------
Helping people is my job...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top