mark_c wrote:we said that if I instantiate n threads without arrays, I lose all references and, if I want to do something about one of them, I can no longer do anything.
Not true. Go re-read what I actually said about that.
mark_c wrote:By setting the FreeOnTerminate = true property; it is true that a thread is terminated at its end
A thread is ALWAYS terminated when it ends, regardless of the TThread::FreeOnTerminate property (if you are using TThread to begin with, vs std::thread). The TThread::FreeOnTerminate property merely controls whether or not the owning TThread object is freed from memory after the thread terminates. If true, the object is freed automatically after its Execute() method exits and its OnTerminate event has been fired. If false, the object is not freed until you explicitly free it yourself.
mark_c wrote:if for some reason an infinite wait is generated in the thread, a loop out of control, I can no longer terminate the thread.
Correct, which is why it is your responsibility to code tour threads properly to avoid such blockages.
mark_c wrote:I would like to try to instantiate 100 threads without arrays and every time one ends, instantiate a new one in its place.
If you use TThread, you can use its OnTerminate event for that purpose. The Sender parameter tells you which TThread object has terminated. I gave you an example of that earlier.
If you use std::thread, there is no such event, so you would have to start a new thread inside your thread function before it exits.
But, either way, this is not really a good design to start a new thread when a thread ends. You should just re-use the existing thread instead. For instance, create a thread-safe work queue, then create some threads to process that queue. Ideally, you should not have more threads than you have CPU cores, maybe a few more, but not much more. Put some work items in the queue, and have each thread loop, pulling an item from the queue on each loop iteration, until the queue is empty.
mark_c wrote:In this way, I wouldn't have the problem of looking every time in the array for what number of threads has been terminated and replacing it with a new one, the index of the array, what do I need if everything is executed and terminated almost automatically?
Ultimately, you should keep track of your threads, and an array is a good way to do that. If nothing else, when you want to exit your program, you need to terminate any threads that are still running, which means knowing which threads exist so you can signal them, which means keeping track of them.
Unless you use a global signal, and keep track of a counter of running threads, and then you can simply signal the global and wait for the counter to hit 0, at least then you don't need to track the individual threads.
mark_c wrote:the idea in untested code
First, that code does not belong in the thread's Execute() at all. That is the code I gave you that belongs in the main UI thread instead to start the initial threads.
Second, you are not managing your global variables correctly, either.
Try this instead:
Code: Select all
int ThreadsRunning = 0;
bool Exiting = false;
class TMyThread : public TThread
{
protected:
void __fastcall Execute();
public:
String name;
__fastcall TMyThread(String AName);
};
__fastcall TMyThread::TMyThread(String AName)
: TThread(true), name(AName)
{
FreeOnTerminate = true;
}
void __fastcall TMyThread::Execute()
{
// do some work...
// check Exiting as needed...
}
__fastcall TForm1::TForm1(TComponent *Owner)
{
try
{
for(int i = 0; i < 100; ++i)
{
TMyThread *TMyTh = new TMyThread("adr_" + IntToStr(i+1));
TMyTh->OnTerminate = &ThreadTerminated;
TMyTh->Resume();
++ThreadsRunning;
}
} catch(...){ }
Caption = "Start " + IntToStr(ThreadsRunning) + " threads created";
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
Exiting = true;
while (ThreadsRunning > 0)
CheckSynchronize();
}
void __fastcall TForm1::ThreadTerminated(TObject *Sender)
{
--ThreadsRunning;
if ((ThreadsRunning < 100) && (!Exiting))
{
TMyThread *TMyTh = static_cast<TMyThread*>(Sender);
TMyTh = new TMyThread(TMyTh->name);
TMyTh->OnTerminate = &ThreadTerminated;
TMyTh->Resume();
++ThreadsRunning;
}
}
//---------------------------------------------------------------------------