My problem is that I have instanciated two TThread (from Borland C++ VCL). Both of their constructors succeeds. But only the first TThread is executed.
(The goal of this code is to load around 100 png image files in a list of Texture Objects; these texture objects (TMyObject) has a "LoadFromFile" function which lasts around 60 ticks).
I have browsed lots of explanations concerning multithreading, and have therefore :
- tried to construct the TMyThread as Suspended (:TThread(true)) and called Resume() for each one
- tried to use TCriticalSection, or also CRITICAL_SECTION, (first as a member of TMyThread ... , then as a member of TMainObject with a pointer to it passed to each TMYThread ... , then as a global variable declared at the side of TMainObject and TMyThread)
- tried to add __thread in the declaration of the member of TMainObject passed to each TMyThread
- tried to call Application->ProcessMessages() in each TMyThread constructor and Execute function
- tried to use a "bool *" passed to each TMyThread to lock and unlock the common memory accesses
- tried unsuccessfully to declare a std::mutex
- tried to call Synchronize(NULL, NULL, 0,0) before the critical memory accesses in order to have the threads reattached to the main thread during these operations
- tried to use two pairs of different lists for each thread
- found this interesting but need help to implement it : http://delphi.about.com/gi/o.htm?zi=1/XJ&zTi=1&sdn=delphi&cdn=compute&tm=41&f=00&tt=14&bt=0&bts=1&zu=http%3A//www.midnightbeach.com/jon/pubs/MsgWaits/MsgWaits.html
- this also : http://delphi.about.com/od/kbthread/a/threaded-delphi-tasks-thread-pool-otl-omnithreadlibrary-example.htm
- read about OTL and ASyncCalls here : How Do I Choose Between the Various Ways to do Threading in Delphi?
=> no success in all these tries.
Here below is my code that I tried to simplify. Any help or explanation would help to make my second Thread been executed.
//---------------------------------------------------------------------------
class TMainClass
{
private:
TMyList<SmartPtr<TEvent> > mEventList;
SmartPtr<TMyThread> mThread1, mThread2;
int mCount;
protected:
int mCurrent, mLast;
TMyList<SmartPtr<TMyObject> > mObjectList;
TMyObject *mpObject;
void MyInit();
public:
TMainObject(TMyParentObject *parent);
virtual ~TMainObject();
virtual void PeriodicTask();
};
//---------------------------------------------------------------------------
class TMyThread : public TThread
{
TMyList<SmartPtr<TEvent> > *mpEventList;
TMyList<SmartPtr<TMyObject> > *mpObjectList;
int mStart, mEnd;
public:
TMyThread( TMyList<SmartPtr<TEvent> > *pEventList,
TMyList<SmartPtr<TMyObject> > *pObjectList,
int Start, int End);
virtual void __fastcall Execute(void);
};
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
TMainClass::TMainClass(TMyParentObject *parent)
{
mCount = 0;
}
TMainClass::~TMainClass()
{
if (mThread1.GetPtr() != NULL)
{
mThread1->Terminate();
mThread1 = SmartPtr<TMyThread> (NULL);
}
if (mThread2.GetPtr() != NULL)
{
mThread2->Terminate();
mThread2 = SmartPtr<TMyThread> (NULL);
}
mpObject = NULL;
mObjectList.Clear();
mEventList.Clear();
}
void TMainClass::MyInit()
{
if (mThread1.GetPtr() != NULL) return;
mObjectList.Clear();
mEventList.Clear();
mCount = GetNumberOfFiles("C:/MyPath/");
for (int i = 1; i <= mCount; i++)
{
SmartPtr<TEvent> lEvent (new TEvent(NULL, false, false, ""));
lEvent.GetPtr()->ResetEvent();
mEventList.Add(lEvent);
}
mThread1 = SmartPtr<TMyThread> (new TMyThread(&mEventList, &mObjectList, 1, floor(mCount/2.0) )); // lock before that ?
mThread2 = SmartPtr<TMyThread> (new TMyThread(&mEventList, &mObjectList, floor(mCount/2.0)+1, mCount )); // lock before that ?
mCurrent = 0;
}
void TMainClass::PeriodicTask()
{
mpObject = NULL;
int lCount = mObjectList.Count();
if (lCount != 0)
{
++mCurrent;
mCurrent = min(mCurrent, lCount);
if ( mLast != mCurrent
&& mEventList[mCurrent]->WaitFor(120) != wrSignaled )
return;
mLast = mCurrent;
mpObject = mObjectList[mCurrent].GetPtr(); // lock before that ?
}
if (mpObject == NULL) return;
mpObject->MyObjectUtilisation(); // lock before that ?
}
//---------------------------------------------------------------------------
TMyThread::TMyThread( TMyList<SmartPtr<TEvent> > *pEventList, TMyList<SmartPtr<TMyObject> > *pObjectList,
int Start, int End);
:TThread(false)
{
mpEventList = pEventList; // lock before that ?
mpObjectList = pObjectList; // lock before that ?
mStart = Start;
mEnd = End;
FreeOnTerminate = false;
}
void __fastcall TMyThread::Execute(void)
{
for (int i = mStart; i <= mEnd; i++)
{
try
{
if (mpEventList != NULL && mpObjectList != NULL)
{
SmartPtr<TMyObject> pObject (new TMyObject());
pObject->LoadFromFile(i);
// common memory accesses before which I want to put a lock
mpObjectList->Insert(i,pObject);
mpEventList[i]->SetEvent();
// place where I could release this lock
}
}
catch(Exception &e)
{
ShowMessage("Exception in Execute : " + e.Message);
}
}
return;
}
Cheers, Arnaud.