hello friends i have a doubt regarding thread count. i have some code written below for thread
Procedure Mainthread.execute;
var
I : integer;
ScannerCh : array of ScannerChild; //array of ScannerChild
IpList : TStringlist;
IPs: Integer; //ipcount is count of iplist
Begin
IpList:=TStringList.Create;//creating stringlist
IPs := IpList.Count; //Ipcount is given value of iplists count
SetLength(ScannerCh, IPs); //Setting length of scannerch as ipcount
I:=0;
Repeat
While getthreadscount(getcurrentprocessid) >= tcount + 1(for main thread + Scannerch threads) do //Checking if is greater than tcount(thread input) by user
Sleep(30);
ScannerCh[I]:=ScannerChild.Create(True, IpList[i]);
ScannerCh[I].FreeOnTerminate:=True;
ScannerCh[I].LvHostname := LvHosts;
ScannerCh[I].Resume;
I:=I+1;
Sleep(20); //Sleep after each thread is created so that threads will enter critical section properly
until I = IPs;
end;
Scannerchild thread does some work. my code works perfectly if i have only these threads in process. If there are some other threads running to then i will be in trouble getting threadscount by getthreadscount function and i will not get to know which threads are getting terminated by getthreadcount function. so how can i enhance my code for many threads working. My logic is when scannerch thread terminates it should decrement count variable and when it gets created it should increment count variable. so that it will not be any problem if other threads are terminated or not. i just want to deal with scannerch thread termination and need to get counts of instances of running threads of scannerch. so that i put count variable instead of getthreadscount and my problem will be solved
Well, the question is easy enough to answer. Declare a count variable in the main thread class:
FScannerChildCount: Integer;
Whenever you create a new thread, increment this variable. Whenever a thread terminates, decrement it.
The incrementing is easy to do since you create the threads quite clearly and explicitly in the main thread code.
As for the decrementing, you need an OnTerminate event handler for each scanner child thread instance. This executes in the context of the process main thread, rather than your MainThread thread. FWIW, MainThread is a terrible name since everyone takes main thread to mean the main process thread. Because the OnTerminate event doesn't run in the same thread as your MainThread thread, you'll need synchronization.
When you increment the thread, use InterlockedIncrement. And when you decrement, use InterlockedDecrement.
The OnTerminate handler might look like this:
procedure MainThread.ScannerChildTerminate(Sender: TObject);
begin
InterlockedDecrement(FScannerChildCount);
end;
And you assign the event like any other event handler:
ScannerCh[I] := ...;
....
ScannerCh[I].OnTerminate := ScannerChildTerminate;
....
ScannerCh[I].Resume;
All of this said, whilst this may be the answer to the question you asked, you are attempting to solve your problem the wrong way. You should be using a thread pool to simplify the coding and avoid the overhead of creating and destroying short lived threads.
Related
I have a procedure (let's call it proc1) that is called inside another one (mainproc) and from time to time the procedure proc1 hangs or executes for a time not worth waiting. mainproc is called inside the main thread. I would like to know what is the best decision in a case like this - is there a way to detect if the procedure won't respond after a certain amount of time without multithreading and if not what is the best way to handle the wait with threads :
procedure proc1;
begin
// statements that can be executed in a few milliseconds or much slower
end;
procedure mainproc;
begin
// statements part1
proc1;
// statements part2
end;
You need a guard thread monitoring entering and exiting of proc1.
For example, the proc1 sets an autoreset signalling event A on entering and sets an autoreset signalling event B on exiting; the guard thread is infinitely waiting on the event A; when A occurs the guard thread starts waiting for the event B for a given timeout; if timeout occurs then proc1 is hanging.
I am trying to make this program using multi thread with delphi it doesn't seem to be going through multiple items just goes through the last one every time instead of selecting multiple
You can see the pic it will explain that it only goes to the last and not the rest of the items
Any Help is great thanks!
procedure TForm1.Button1Click(Sender: TObject);
var
Index2: Integer;
begin
for Index2 := 0 to ListBox2.Items.Count - 1 do
begin
ListBox2.ItemIndex := Index2;
LastName := ListBox2.Items.Strings[Index2];
with T1.Create do
FreeOnTerminate := True;
end;
end;
Your program runs through the 4 items in your listbox, and for each item it starts a thread (that runs in the background) and then continues with the next item in the listbox - even though the thread hasn't finished processing.
If you in your T1 thread reads the ListBox2.SelectedIndex, then it will most likely read the last item, as your thread will most likely only reach the reading of the SelectedIndex after the FOR loop has finished. Remember that the thread you are starting is running simultaneously as your main thread, ie. your main thread doesn't suddently stop running just because you start a new thread (that's the whole point of multi-threading).
Instead, you should pass the index for the thread to process into the thread as you are creating it, by re-making the Create CONSTRUCTOR to accept a listbox and/or the item to process, or - even better - do the readout of the data you need from the ListBox2 and pass that onto the Create CONSTRUCTOR of the thread. You should not access VCL components from threads - especially not if those same components are updated in the main thread at the same time (which is what is the problem here).
I have the following scenario:
The program I am writing simulates multiple air networks. Now I have written it so that each simulation is in its own thread with its own data. This is so that there can be no contamination of data and each thread is complete multitasking safe. I have implemented delphi's native TThread class for each thread.
The program has one main thread. It then creates multiple sub threads for each network (my current test case has 6). But each sub thread also has 4 additional threads since its network has more than one layout. So in total I have 31 threads, but only 24 threads actively processing. All threads are created in suspended mode so that I can manually start them.
The computer I am running on is an i5 laptop so it has 4 threads (2 physical cores + 2 HT). In the production environment this will run on servers so they will have more processing power.
Now in the main program thread I have added a break point after the for loop which executes the threads. This doesn't trigger immediately. Watching the debug console of Delphi, it looks like it is only actively running 4 threads at a time. As soon as one exits, it starts another thread.
The simulations in the threads are difficult to optimize and require a few loops to finish the simulation. And each loop requires the previous loop's data. But each simulation is completely independent of the next so the program is an excellent candidate for threads and pipe lining.
Now my question is why does it only start 4 threads and not all the threads as the code specifies?
EDIT Added pieces of code
Main program
for i := 0 to length(Solutions)-1 do
begin
Solutions[i].CreateWorkers; //Setup threads
end;
for i := 0 to length(Solutions)-1 do
begin
Solutions[i].Execute; //start threads
end;
end;
isSolversBusy := false; //breaking point doesn't trigger here
1St level of threads
procedure cSolution.Execute;
var
i : integer;
lIsWorkerStillBusy : boolean;
begin
lIsWorkerStillBusy := true;
for i := 0 to length(Workers)-1 do
begin
Workers[i].Start;
end;
while (lIsWorkerStillBusy) do
begin
lIsWorkerStillBusy := false;
for i := 0 to length(Workers)-1 do
begin
if Workers[i].IsCalculated = false then
begin
lIsWorkerStillBusy := true;
end;
end;
sleep(100);
end;
FindBestNetwork;
IsAllWorkersDone := true;
end;
2nd level of threads
procedure cWorker.Execute;
begin
IsCalculated := false;
Network.UpdateFlows;
Network.SolveNetWork; //main simulation work
CalculateTotalPower;
IsCalculated := true;
end;
EDIT 2
The reason I create them all suspended is because I store them in an array and before I start them I first have create the workers and their properties. I am simulating air network scenarios. Each solution is a different layout, while each worker is a different way of running that layout.
I have to first calculate all the worker's start properties before I start them all. In hind sight I could modify the code to do that in the thread. It currently happens in the main thread. The creation of the threads happens before the piece of code I pasted here.
The reason I keep them all in threads is that I need to evaluate the results of each thread afterwords.
This is your problem :
for i := 0 to length(Solutions)-1 do
begin
Solutions[i].Execute; //start threads
end;
This does not start the threads - this is executing the Execute method in the calling thread. In fact you were not running only 4 threads at a time, you were not even running one - all of this work would be done on the main thread sequentially. To resume a suspended thread you must use Solutions[i].Start.
The Execute method of a TThread is a special method that is executed on the worker thread created by the TThread automatically. When you create a TThread this method is automatically run on the worker thread that the TThread creates. If you create the thread suspended then it simply waits for you to wake the thread before beginning this work. Calling the .Start method of a TThread is what accomplishes this - triggering the underlying worker thread to begin executing the .Execute method.
Otherwise, the Execute method, and all other methods of a TThread are no different from any other normal method belonging to a class. They can be executed on any thread that calls them directly.
In this case, it doesn't seem like you are doing any additional work in the main thread between creating and executing your workers. In this case, unless you have an explicit need for it, you could simply create your threads not-suspended and let them execute automatically upon creation.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I run a multithread application and I want to limit the number of threads on my machine
The code concept goes currently like this (it is just a drft to show the major ideas behind)
// a List with all the threads I have
class MyTHreadList = List<TMyCalcThread>;
// a pool class, check how many threads are active
// try to start additions threads once the nr. of running THreads
// is below the max_thread_value_running
class MyTheardPool = Class
ThreadList : MyTHreadList;
StillRunningTHreads : Integer;
StartFromThreadID : Integer;
end;
var aTHreadList : MyTHreadList;
procedure MainForm.CallCreateThreadFunction( < THREAD PARAMS > );
begin
// just create but do not start here
MyTHread := TMyCalcThread.create ( < THREAD PARAMS > );
MyTHread.Onterminate := What_To_do;
// add all threads to a list
aTHreadList.add(MyTHread);
end;
/// (A)
procedure MainForm.What_To_do ()
var start : Integer;
begin
max_thread_value_running := max_thread_value_running -1;
if max_thread_value_running < max_thread_count then
begin
start := max_thread_count - max_thread_value_running;
startThereads(start,StartFromThreadID)
end;
end;
procedure MainForm.startThereads (HowMany , FromIndex : Integer);
var i : INteger;
begin
for I := FromIndex to HowMany + FromIndexdo
begin
// thread[i].start
end;
end;
MainForm.Button ();
/// main VCL form , create threats
for i := 0 to allTHreads do
begin
CallCreateTHreadFunction( < THREAD PARAMS > );
end;
......
/// (B)
while StillRunningTHreads > 0 do
begin
Application.processmessages;
end;
The complete idea is a small list with the Threads, on every individual Thread terminate step I update the number of running threads and start the now possible max. number of new threads.(A) Instead of a Function WaitforSingleObject () .... I do a loop at the end to wait for all threads to finish execution. (B)
From the code design I did not find any full example on the net, I may approach a vaild design or will I run into some trouble which I did not consider right now.
Any comment on the diesign or a better class design is welcome.
Don't try to micro-manage threads like this. Just don't. Either use the Win API threadpool calls, or make your own threadpool from a producer-consumer queue and TThread instances.
When a task is completed, I suggest that the work thread call an 'OnCompletion' TNotifyEvent of the task class with the task as the parameter. Ths can be set by the issuer of the task to anything they might wish, eg. postMessaging the task instance to the GUI thread for display.
Micro-managing threads, continually creating/waiting/terminating/destroying, Application.processmessages loops etc. is just horrible and almost sure to go wrong at some point.
Waiting for ANYTHING in a GUI event-handler is just bad. The GUI system is a state-machine and you should not wait inside it. If you want to issue a task from the GUI thread, do so but don't wait for it - fire it off and forget it until it is completed and gets posted back to a message-handler procedure.
Basically thread-pools are a nice feature (There is an implementation in the Win32 API, however I don't have any experience with it).
There is one basic stumble stone however: You need to remember that a task may be delayed until an empty thread is available. If you need synchronization between different tasks (e.g. tasks are waiting on other tasks) then you have a serious deadlock problem:
Just assume that all running tasks wait for a single task which is waiting for a free thread...
A similar problem can also happen if your threads wait for the main thread to react while the main thread waits for a new task to start.
If your tasks don't need any further synchronization (e.g. once a task is finished it will just mark itself as finished and the main thread will then later on read the result) you don't need to worry about this.
As a small side note:
I would use two separate lists: One for free (suspended) threads and one for running threads.
I'd consider to use an existing Thread-Pool implementation (like Winapi CreateThreadpool) before I created my own...
The loop (B) takes away a lot of CPU power from the threads. Don't wait actively in a loop for threads, use one of the WaitFor.... functions.
Reuse your threads and have a list of "todos" that the threads will execute. Thread creation and destruction can be expensive.
Apart from that I'd recommend that you use an existing library instead of reinventing the wheel. Or use at least the Windows API thread pool functions.
I'm working with a simple static thread pool, where there are 4 threads, each with a queue, that process individual lines from a string list. After each thread has completed one of the requests in its queue, it synchronizes an event, which is handled in the parent thread. This is done by calling DoComplete() after it's done, like so:
procedure TDecoderThread.DoComplete(const Line: Integer; const Text: String);
begin
FLine:= Line;
FText:= Text;
Synchronize(SYNC_OnComplete);
end;
procedure TDecoderThread.SYNC_OnComplete;
begin
if assigned(FOnComplete) then
FOnComplete(Self, FText, FLine); //Triggers event which is handled in parent thread
end;
On the other end, in their parent thread, these events are handled with this procedure:
procedure TDecoder.ThreadComplete(Sender: TDecoderThread; const Text: String;
const Line: Integer);
begin
FStrings[Line]:= Text; //Updates the original line in the list with the new text
end;
Since I have 4 different threads, each of which might call this OnComplete() event at the same time as each other, do I also have to worry about thread protecting this FStrings: TStrings? Could two threads triggering their OnComplete() event at the same time cause a deadlock in their parent thread when writing to this string list? Or would the main thread be smart enough to wait until one of them is done before handling the other?
PS - Yes, this little project was an attempt to answer another previous question from someone else here on SO, which has been answered far differently, but in order to get myself a little more familiar with multi-threading, I continued this sample project anyway.
Since the OnComplete event is being triggered by Synchronize(), you do not need to use a thread-safe lock around the FStrings list, since all access to the list is being delegated through the main thread, so only one OnComplete event handler can actually run at a time. If you were not using Synchronize(), you would need such a lock around FStrings if items are being added/removed and thus reallocating the list memory, or if other threads were reading the values from FStrings, while the threads were still running. If the processing threads are the only ones accessing FStrings, there is no risk for concurrent access of the individual items, so no lock would be needed.