我的问题是我已经实现了两个TThread(来自Borland C ++ VCL)。 他们的两个构造者都成功了。 但只执行了第一个TThread。
(此代码的目标是在纹理对象列表中加载大约100个png图像文件;这些纹理对象(TMyObject)具有“LoadFromFile”函数,该函数持续大约60个刻度。)
我浏览了很多关于多线程的解释,因此:
=>在所有这些尝试中都没有成功。
以下是我试图简化的代码。 任何帮助或解释都有助于我的第二个Thread被执行。
//---------------------------------------------------------------------------
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;
}
干杯, 阿诺。
答案 0 :(得分:0)
好的,我做了一个使用线程的PNG加载器的例子(实际上是一个线程池)。它与您的设计略有不同,但它可以正常工作。我试图获取标题中的所有代码以便更容易发布,但依赖项不允许它,所以我也必须有一点cpp。我创建了一个显示幻灯片放映的测试表单,所以我也包含了该代码。
// HPP标题:
#ifndef PNGloaderH
#define PNGloaderH
#include <Classes.hpp>
#include <deque.h>
#include <vector.h>
#include <PngImage.hpp>
#include <usefulStuff.hpp>
class CBthreadPool;
// Task class to inherit from, supplying the abstract run() method.
class CBtask {
friend class CBthreadPool;
friend class TpoolThread;
CBthreadPool *myPool;
TNotifyEvent FonComplete;
protected:
int param;
virtual void DoCompleted(){ // called after run, normall calls OnComplete
if (FonComplete!=NULL){FonComplete((TObject*)this);};
delete(this);
}
public:
String errorMess;
CBtask(int inParam, TNotifyEvent OnComplete){ // user param and
FonComplete=OnComplete; // an OnComplete callback to be called after run()
param=inParam;
};
virtual void run()=0;
void submit(CBtask *aTask);
};
// Producer-Consumer queue for tasks
class CBSqueue{
TCriticalSection *access;
deque<CBtask*> workQueue;
TSemaphore *queueSema;
public:
CBSqueue(){
access=new TCriticalSection();
queueSema=new TSemaphore(NULL,0,MAXINT,NULL,false);
};
void push(CBtask *task){
access->Acquire();
workQueue.push_front(task);
access->Release();
queueSema->Release();
};
bool pop(CBtask **task,DWORD timeout){
if(wrSignaled==queueSema->WaitFor(timeout)){
access->Acquire();
*task=workQueue.back();
workQueue.pop_back();
access->Release();
return(true);
} else return false;
};
};
// Threadpool thread
class TpoolThread : public TThread{
CBthreadPool *FmyPool;
protected:
virtual void __fastcall Execute(void);
public:
TpoolThread(CBthreadPool *myPool):TThread(true){
FmyPool=myPool;
Resume();
};
};
// General purpose threadpool
class CBthreadPool {
friend class TpoolThread;
int threadCnt;
CBSqueue taskQueue; // P-C queue of CBtask, (or descendants)
public:
CBthreadPool(int numThreads){
for(threadCnt=0;threadCnt<numThreads;threadCnt++){new TpoolThread(this);}
} // crate all the thradpool threads, passing them the queue to wait on
void submit(CBtask *aTask){ // method to submit work
aTask->myPool=this; // in case the task wants to issue any tasks
taskQueue.push(aTask); // off it goes..
};
};
/* This CBtask descendant has a 'run' method that loads 'thePNG' object
from a filespec passed in ctor. Instances of this class are queued to the
thread pool to load the PNG files */
class PNGtask:public CBtask{
String Ffolder;
public:
TPngImage *PngImage;
void run(){
PngImage=new TPngImage;
PngImage->LoadFromFile(Ffolder);
};
PNGtask(String dir,TNotifyEvent OnDone):CBtask(0,OnDone){Ffolder=dir;};
};
/* This CBtask descendant has a 'run' method that iterates a folder passed in
the ctor for 'PNG' files, submits a PNGtask for each one and waits for the last
to complete. One is issued to the pool for each folder to be searched */
class PNGfilesTask:public CBtask{
String Ffolder;
int taskCounter;
TEvent *CompleteEvent;
TCriticalSection *counterLock;
public:
vector<TPngImage*> *PngImages;
TObject *userData;
PNGfilesTask(String folder, TNotifyEvent OnComplete,
vector<TPngImage*> *PngImages,TObject *UserData):CBtask(0,OnComplete){
Ffolder=folder;
this->userData=UserData;
CompleteEvent=new TEvent(NULL,false,false,"",false);
counterLock=new TCriticalSection();
this->PngImages=PngImages;
}
void run(){ // get all the file names
TStringList *files=listAllFilesInThisFolderMatching(Ffolder,"*.png");
taskCounter=files->Count; // set the task counter
for (int i=0; i<files->Count; i++) { // submit a PNGtask for each file
PNGtask *aTask=new(PNGtask)(Ffolder+"\\"+files->Strings[i],OnFilesLoaded);
submit(aTask);
}
delete(files);
CompleteEvent->WaitFor(INFINITE); // and wait for the last one to finish
};
void __fastcall OnFilesLoaded(TObject *Sender){ // called by each PNGtask
counterLock->Acquire(); // thread-safe
PngImages->push_back(((PNGtask*)Sender)->PngImage); // PNGImage into vector
if(--taskCounter==0){ // all loads done?
CompleteEvent->SetEvent(); // signal the run() method to continue
};
counterLock->Release();
};
};
/* This class inherits from threadpool and has a 'PNGget' method that takes a
folder path, a pointer to a caller-supplied vector that will be loaded with
TPngImage* instances, an 'OnComplete' callback and a user context object.
When the files are all loaded, the 'OnComplete' event is called with the
PNGfilesTask object as the Sender. */
class PNGload:public CBthreadPool{
public:
PNGload(int numThreads):CBthreadPool(numThreads){
}
void PNGget(String folder,vector<TPngImage*> *results,
TNotifyEvent OnComplete, TObject *userData){
PNGfilesTask *loadPNG=new(PNGfilesTask)(folder,OnComplete,results,userData);
submit(loadPNG); // execute loadPNG->run() on the threadpool
};
};
#endif
// CPP文件
#include "PNGloader.hpp"
void __fastcall TpoolThread::Execute(){
CBtask *thisTask;
while(FmyPool->taskQueue.pop(&thisTask,INFINITE)){
try{
if(thisTask!=NULL){
thisTask->errorMess="";
thisTask->run();
}
else{
FmyPool->taskQueue.push(thisTask);
exit;
}
}
catch(exception& e){
thisTask->errorMess=e.what();
}
thisTask->DoCompleted();
thisTask;
}
};
void CBtask::submit(CBtask *aTask){
myPool->submit(aTask);
}
//测试表单 - 允许用户选择一个文件夹,然后显示任何PNG的幻灯片 里面的文件。顶部有一个面板,一个按钮和一个标签,一个计时器,表格的下半部分都是TImage。
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "PNGform.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfoPNGload *foPNGload;
//---------------------------------------------------------------------------
__fastcall TfoPNGload::TfoPNGload(TComponent* Owner)
: TForm(Owner)
{
myLoad=new PNGload(10);
}
//---------------------------------------------------------------------------
void __fastcall TfoPNGload::SpeedButton1Click(TObject *Sender)
{
if(PathName==""){PathName="C:\\";};
if (SelectDirectory("Select Directory",PathName,PathName)){
myLoad->PNGget(PathName,new(vector<TPngImage*>),filesLoaded,NULL);
}
}
//---------------------------------------------------------------------------
void __fastcall TfoPNGload::filesLoaded(TObject *Sender){
vector<TPngImage*> *PngImages;
PngImages=((PNGfilesTask*)Sender)->PngImages;
PostMessage(Handle,WM_APP,0,long(PngImages));
};
void __fastcall TfoPNGload::WMAPP(TMessage& msg){
vector<TPngImage*> *thisVectorPtr=(vector<TPngImage*>*)msg.LParam;
resultList.push_back(thisVectorPtr);
vecSize=thisVectorPtr->size();
if (vecSize>0) tiSlideShow->Enabled=true;
};
void __fastcall TfoPNGload::getNextVector(){
if (resultList.size()!=0) {
currentPNG=resultList.back();
resultList.pop_back();
currentPNGindex=0;
}
else
currentPNG=NULL;
};
void __fastcall TfoPNGload::tiSlideShowTimer(TObject *Sender)
{
if(currentPNG==NULL) getNextVector();
else
if (currentPNG->size()==0) {
delete(currentPNG);
getNextVector();
}
if(currentPNG==NULL) {
tiSlideShow->Enabled=false;
Label1->Caption="No files left";
return;
};
TPngImage *thisPNG;
Label1->Caption=IntToStr((int)currentPNG->size())+" PNG files left";
thisPNG=currentPNG->back();
currentPNG->pop_back();
Image1->Picture->Assign(thisPNG);
delete(thisPNG);
}
//---------------------------------------------------------------------------
//表格标题
//---------------------------------------------------------------------------
#ifndef PNGformH
#define PNGformH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
#include <Dialogs.hpp>
#include <ExtCtrls.hpp>
#include <PngImage.hpp>
#include "Pngloader.hpp"
#include "PNGform.h"
//---------------------------------------------------------------------------
class TfoPNGload : public TForm
{
__published: // IDE-managed Components
TImage *Image1;
TPanel *Panel1;
TSpeedButton *SpeedButton1;
TTimer *tiSlideShow;
TLabel *Label1;
void __fastcall tiSlideShowTimer(TObject *Sender);
void __fastcall SpeedButton1Click(TObject *Sender);
private:
PNGload *myLoad;
String PathName;
void __fastcall filesLoaded(TObject *Sender);
void __fastcall getNextVector();
protected:
MESSAGE void __fastcall WMAPP(TMessage& msg);
public: // User declarations
__fastcall TfoPNGload(TComponent* Owner);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_APP, TMessage, WMAPP)
END_MESSAGE_MAP(TForm)
vector < vector<TPngImage*>* > resultList;
vector<TPngImage*> *currentPNG;
int currentPNGindex;
int vecSize;
};
//---------------------------------------------------------------------------
extern PACKAGE TfoPNGload *foPNGload;
//---------------------------------------------------------------------------
#endif