Developer forums (C::B DEVELOPMENT STRICTLY!) > Development
Revamping Code Completion with little changes
zieQ:
--- Quote from: mandrav ---Why a singleton? You could have many different pools (if needed). Why restrict yourself to just one global pool?
One pool for code-completion, one for compiler, etc.
And the compiler could use thread pooling. Each wxExecute could be executed in a thread pool worker class...
Yiannis.
--- End quote ---
Well, singleton due to the pool dimensioning. There is an optimal value for the number of threads for the best performance that would not be guaranteed if there are many pools, especially if the dimension is allowed to vary during runtime by analyzing the workload. Did you read the second link I posted? I may be wrong however, we may propose a simplified version with no adjustement of the number of threads but I don't think that many pools is a good idea anyway. To me, thread pools are a collection of threads (optimal number dependending on the machine and the type of workload, which vary during runtime in our case) and a collection of (independent) tasks to be accomplished by the given number of threads. If tasks are independent, there's no need to separate pools for each kind of task to perform. We then can mix parsing with compilation, etc.
Second remark, I don't see any way for the compiler to use the thread pool. AFAIK, there is no method that link a wxThread to a wxProcess and conversely, and wxExecute deals with wxProcess while the thread pools deals with wxThread. Can you explain how you would do it? Maybe I am blind :p
--- Quote from: rickg22 ---OK, but if the code completion is going to use the thread pool, how long will I have to wait before the pool's ready so I can make the changes to CC? Or should I begin the changes and later we can switch to using the pool?
--- End quote ---
I think we can define the public interface fast for the pool so you can start redesigning it before the pool is implemented... Just my thought...
rickg22:
AHHHHHHH so something like...
--- Code: ---class ParserTask: public ThreadTask
{
};
--- End code ---
?
mandrav:
OK, here's a *primitive* I 'm working on. It's nowhere near complete API-wise. But hey, let's add some flesh and bones in the discussion ;)
(don't mind the STL in there - we 'll probably use wx replacements for those)
--- Code: ---#ifndef CBTHREADPOOL_H
#define CBTHREADPOOL_H
#include <queue>
#include <vector>
#include <wx/event.h>
#include <wx/thread.h>
extern int idThreadPoolMsg;
// flags
#define DELETE_WORKER_WHEN_DONE 0x01
/// Abstract base class for workers assigned to the thread pool object
/// Derive a class from this and perform your thing in Execute()
/// It's like wxThread, except it's not a thread anymore ;)
class cbThreadPoolWorker
{
public:
virtual int Execute() = 0;
};
// forward decl
class PrivateThread;
/// Definition of a Thread Pool Object (used by thread pool only)
struct cbThreadPoolObject
{
cbThreadPoolObject() : pThread(0), pWorker(0), flags(0) {}
cbThreadPoolObject(const cbThreadPoolObject& rhs) : pThread(rhs.pThread), pWorker(rhs.pWorker), flags(rhs.flags) {}
PrivateThread* pThread;
cbThreadPoolWorker* pWorker;
int flags;
};
/// The main thread pool object.
class cbThreadPool
{
public:
cbThreadPool(wxEvtHandler* owner, int id = -1, int concurrentThreads = -1);
virtual ~cbThreadPool();
virtual void SetConcurrentThreads(int concurrentThreads);
virtual bool AddThread(cbThreadPoolWorker* worker, bool deleteWhenDone = false);
virtual void RemoveThread(cbThreadPoolWorker* worker);
protected:
virtual void AllocThreads();
virtual void FreeThreads();
virtual void ScheduleThreads();
void Log(const wxString& msg);
wxEvtHandler* m_pOwner;
int m_ID;
std::queue<cbThreadPoolObject> m_Pool;
std::vector<PrivateThread*> m_Workers; // worker threads
int m_ConcurrentThreads;
int m_MaxThreads;
};
/// Base thread class
class PrivateThread : public wxThread
{
public:
enum State
{
Idle,
Busy
};
enum Status
{
LaunchJob,
Quit
};
PrivateThread(cbThreadPoolWorker* worker = 0)
: m_Condition(m_Mutex),
m_pWorker(worker),
m_Status(Quit),
m_State(Idle)
{
m_Mutex.Lock();
}
~PrivateThread(){}
void SetWorker(cbThreadPoolWorker* worker);
void SetStatus(Status status);
State GetState(){ return m_State; }
virtual ExitCode Entry();
protected:
friend class cbThreadPool; // allow thread pool to access the mutex and the condition object
wxMutex m_Mutex;
wxCondition m_Condition;
cbThreadPoolWorker* m_pWorker;
Status m_Status;
State m_State;
private:
};
#endif // CBTHREADPOOL_H
--- End code ---
The way it would work is like:
--- Code: ---class ParserThread : public cbThreadPoolWorker
{
...
int Execute(); // override pure virtual
...
};
// set the max nr of concurrent threads to run
// -1 means "number of CPUs" (yes it works with HyperThreading ;) )
g_ThreadPool.SetConcurrentThreads(-1);
// pass a new "thread" to the pool; it 'll run when the pool has available resources
g_ThreadPool.AddThread(new ParserThread);
--- End code ---
Yiannis.
Urxae:
--- Quote from: mandrav on August 22, 2005, 08:21:38 pm ---
--- Code: ---// flags
#define DELETE_WORKER_WHEN_DONE 0x01
/// Abstract base class for workers assigned to the thread pool object
/// Derive a class from this and perform your thing in Execute()
/// It's like wxThread, except it's not a thread anymore ;)
class cbThreadPoolWorker
{
public:
virtual int Execute() = 0;
};
--- End code ---
--- End quote ---
If you're going to call delete on pointers to workers (as that #define implies) you should give them a virtual destructor, so that the derived class gets to run its own constructor as well ;).
mandrav:
--- Quote from: Urxae on August 22, 2005, 09:31:54 pm ---If you're going to call delete on pointers to workers (as that #define implies) you should give them a virtual destructor, so that the derived class gets to run its own constructor as well ;).
--- End quote ---
Right. Although it's early, I can't believe I 've missed it (you 'll see it in cbThreadPool).
Thanks :)
Yiannis.
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version