GNUGK2.2.3一改之前2.0版本版本的單線程結構。採用了作業(Job,Task)-代理(Agent)-執行者(Worker)三層控制結構 。使整個體系結構更加易於擴展和清晰。
在這裏主要分析Job,Task,Agent,Worker他們之間的關係,以及Job的派生類Jobs與RegularJob時等。
理解Job,Agent,Worker三個類之間的關係,需要跟大家複習一下操作系統中的程序,進程,和CPU調度程序。
程序,是一個程序代碼,數據等的集合。
進程,是一個正在運行的搶佔CPU資源的程序。是程序的一個實例。
CPU調度程序,決定了當前那個進程可以運行,可以獲得CPU的控制權限。
在這裏的Job和操作系統中的程序是類似的,我們只要在Job的派生類中的Run函數編寫我們要執行的程序代碼即可。然後創建該Job的一個實例,並把該Job提交給Agent,Agent就會爲該Job非配一個Worker來執行Job中的Run代碼。因此他們之間和操作系統的程序,進程,CPU調度程序的對應關係是:
Job-----------程序
Agent------CPU調度進程
Worker----正在運行的進程
/////////////////////////////////////////////////////job.h//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//
// job.h
//
// Abstraction of threads' jobs
//
//////////////////////////////////////////////////////////////////
#ifndef JOB_H
#define JOB_H "@(#) $Id: job.h,v 1.6 2005/04/24 16:39:44 zvision Exp $"
#include "name.h"
/** The base abstract class that represents job objects.
This class implements the way to execute the job.
Derived classes implement actual jobs (override Run()).
Jobs are executed and managed by internal Job managment system
consisting of the singleton Agent object and Worker threads
that accept and execute new Jobs.
Specialized Job examples are:
Jobs - executes series of Tasks
RegularJob - executes a Task again and again until stopped
SimpleJob - calls some funtion with one pointer-type argument
SimpleJobA - calls some funtion with two arguments : pointer-type and reference
SimpleClassJob - calls a member function of some class that takes no arguments
SimpleClassJobA - calls a member function of some class that takes one
argument of reference type
*/
// Job,代表一個具體要執行的任務
class Job : public NamedObject
{
public:
virtual ~Job();
/// Perform the actual job, return when it is done
/* Job 真正要執行的代碼,只要在派生類實現該函數即可*/
virtual void Run() = 0;
/// Stop a running job
virtual void Stop();
/** Execute the job in a first idle Worker thread.
The function returns immediatelly and this object
is delete automatically, when the job is finished.
使用該函數,把此job提交到Agent,由agent分配執行者
*/
void Execute();
/// Stop all jobs being currently executed by Worker threads
static void StopAll();
};
/** Similar to the Job, but is even more abstract. It does not contain
any Task management routines. Main purpose of this class it to provide
a way to represent a serie of Tasks that are to be executed one after another.
Task是一個比Job更小的執行任務,如果把Job當作操作系統的批處理任務,那麼Task只是其中的一個小任務
*/
class Task
{
public:
Task() : m_next(NULL), m_done(false) {}
virtual ~Task();
/// Perform the actual task and return when it is finished
//Task具體要執行的代碼,在其派生類的函數中要實現Exec這個函數。在調用Job->Run的時候會調用該函數
virtual void Exec() = 0;
/** @return
true if the task is done and a next task is being processed.
*/
bool IsDone() const { return m_done; }
/// Setup a task to be executed when this one is done
//Task是一個單向鏈表結構,設置下一個Task
void SetNext(
/// next task to be executed
Task* next
)
{
if (m_next != NULL && m_next != this)
m_next->SetNext(next);
else
m_next = next;
}
/** @return
true if this is not the last task.
是否還有可執行的Task
*/
bool HasNext() const { return m_next != NULL; }
/** Get a next task and mark this one as done.
@return
The task that is next or NULL if this is the last task.
執行完成一個Task以後,設置下一個要執行的Task,並標識該Task已經執行完成,
done=true
*/
Task* DoNext()
{
Task* next = m_next;
if (next != this) // do not set m_done flag for circular task
m_done = true;
return next;
}
private:
/// next task to be executed when this one is done
Task* m_next;
/// true if the task is finished
bool m_done;
};
/// Execute a task or a serie of tasks
// 重複不斷執行的Job,不是循環的執行某一段共同的代碼
class Jobs : public Job
{
public:
Jobs(
/// task to be executed
Task* task
) : m_current(task) {}
/// process the associated task (override from Job)
virtual void Run();
private:
/// task (or a serie of tasks) to be executed
Task* m_current;
};
/** Regular job - executes the same task until it is stopped
(by calling Stop()). The actual work is to be done in the virtual
Exec() method in derived classes. RegularJob is an abstract class.
順序的執行多個Job,Job與Job之間可以沒有任何關係
*/
class RegularJob : public Job
{
public:
RegularJob();
/** @return
true if the job has not been yet stopped
*/
bool IsRunning() const { return !m_stop; }
/// override from Job
virtual void Run();
/// repeated activity to be executed by this RegularJob
//真正要執行的代碼,在派生類中繼承該函數,就是重複Job要執行的具體代碼
virtual void Exec() = 0;
/** Stop this job. NOTE: Acquire m_deletionPreventer mutex first
to make sure this object is not deleted before the method that
called Stop returns (if Stop is called from a derived class).
*/
virtual void Stop();
protected:
// new virtual function
/// Callback function that is called before the job is started.
virtual void OnStart();
/** Callback function that is called when the job is stopped.
NOTE: This function is called with m_deletionPreventer mutex acquired.
*/
virtual void OnStop();
/// Wait for a signal (Signal())
void Wait() { m_sync.Wait(); }
/** Wait for a signal (Signal()).
@return
true if the sync point has been signalled.
*/
bool Wait(
/// time to wait for the sync point to be signalled
const PTimeInterval& timeout
)
{
return m_sync.Wait(timeout) ? true : false;
}
/// Send a signal to the waiting task
void Signal() { m_sync.Signal(); }
protected:
/// can be used when calling Stop to prevent the job to be deleted
/// (and invalid object being referenced) before the function
/// that called Stop returns
PMutex m_deletionPreventer;
private:
/// used by Wait and Signal member functions
PSyncPoint m_sync;
/// true if the job should be stopped
bool m_stop;
};
用於創建Job的模板,把某個函數或者某個類的成員函數當作一個線程執行
也就是爲函數f,分配一個線程來執行其代碼
template<class F, class T>
class SimpleJob : public Job {
public:
SimpleJob(const F & _f, T *_t) : f(_f), t(_t) {}
virtual void Run() { f(t); }
private:
const F f;
T *t;
};
template<class F, class T, class A>
class SimpleJobA : public Job {
public:
SimpleJobA(const F & _f, T *_t, const A & _a) : f(_f), t(_t), a(_a) {}
virtual void Run() { f(t, a); }
private:
const F f;
T *t;
A a;
};
template<class T>
class SimpleClassJob : public Job {
public:
SimpleClassJob(T *_t, void (T::*_j)()) : t(_t), j(_j) {}
virtual void Run() { (t->*j)(); }
private:
T *t;
void (T::*j)();
};
template<class T, class A>
class SimpleClassJobA : public Job {
public:
typedef void (T::*CJob)(A);
SimpleClassJobA(T *_t, CJob _j, A _a) : t(_t), j(_j), a(_a) {}
virtual void Run() { (t->*j)(a); }
private:
T *t;
CJob j;
A a;
};
template<class T>
void CreateJob(T *t, void (T::*j)(), const char *n)
{
Job *newjob = new SimpleClassJob<T>(t, j);
newjob->SetName(n);
newjob->Execute();
}
template<class T, class A>
void CreateJob(T *t, void (T::*j)(A), A a, const char *n)
{
Job *newjob = new SimpleClassJobA<T, A>(t, j, a);
newjob->SetName(n);
newjob->Execute();
}
#endif // JOB_H
////////////////////////////////////////////////////////job.cxx//////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//
// job.cxx
//
//////////////////////////////////////////////////////////////////
#include <list>
#include <ptlib.h>
#include "stl_supp.h"
#include "rwlock.h"
#include "singleton.h"
#include "job.h"
#include "h323util.h"
// timeout (seconds) for an idle Worker to be deleted
#define DEFAULT_WORKER_IDLE_TIMEOUT (10*60)
/** This class represents a thread that performs jobs. It has two states:
idle and busy. When it accepts a new Job, it becomes busy. When the job
is finished it becomes idle. Each idle Worker is stopped (deleted) after
the specified timeout, so Workers that are not needed anymore do not use
system resources. This makes passible to create dynamic sets of Workers.
*/
class Agent;
class Worker : public PThread
{
public:
PCLASSINFO(Worker, PThread)
/// create a new Worker thread and start it immediatelly
Worker(
/// pointer to the Agent instance that the worker is run under control of
Agent* agent,
/// timeout (seconds) for this Worker to be deleted, if idle
long idleTimeout = DEFAULT_WORKER_IDLE_TIMEOUT
);
~Worker();
/** Tell this Worker to execute a new Job. The function returns
immediatelly and the job is executed under control of the Worker thread.
After the job is finished, its object is deleted.
@return
true if this Worker is idle and has taken the Job, false otherwise
(on failuer the job object is not deleted).
提交job到worker線程,該job是worker下一個要執行的任務
*/
bool Exec(
/// Job to be executed
Job* job
);
/** Stop the Worker thread and any jobs being executed,
wait for Worker thread termination and delete this object.
銷燬Worker對象,不能使用delete,需要自我delete
*/
void Destroy();
PThreadIdentifer GetWorkerId(){ return m_id;};
private:
// override from class PThread
virtual void Main();
/// idle timeout (seconds), after which the Worker is destoyed
PTimeInterval m_idleTimeout;
/// signals that either a new Job is present or the Worker is destroyed
PSyncPoint m_wakeupSync;
/// true if the Worker is being destroyed
bool m_closed;
/// for atomic job insertion and deletion
PMutex m_jobMutex;
/// actual Job being executed, NULL if the Worker is idle
Job* m_job;
/// Worker thread identifier
PThreadIdentifer m_id;
/// Agent singleton pointer to avoid unnecessary Instance() calls
Agent* m_agent;
};
/** Agent singleton manages a set of Worker threads. It creates
new Workers if required. Idle Workers are deleted automatically
after configured idle timeout.
*/
class Agent : public Singleton<Agent>
{
public:
Agent();
~Agent();
/** Execute the job by the first idle Worker or a new Worker.
Delete the Job object after it is done.
*/
void Exec(
/// the job to be executed
Job* job
);
/** Remove the Worker from busy and idle lists.
Called by the Worker when it deletes itself.
*/
void Remove(
/// the worker to be removed from the lists
Worker* worker
);
/** Move the Worker from the busy list to the idle list.
Called by the Worker when it finishes each job.
*/
void JobDone(
/// the worker to be marked as idle
Worker* worker
);
private:
/// mutual access to Worker lists
PMutex m_wlistMutex;
/// list of idle Worker threads
std::list<Worker*> m_idleWorkers;
/// list of Worker threads executing some Jobs
std::list<Worker*> m_busyWorkers;
/// flag preventing new workers to be registered during Agent destruction
bool m_active;
};
Worker::Worker(
/// pointer to the Agent instance that the worker is run under control of
Agent* agent,
/// timeout (seconds) for this Worker to be deleted, if idle
long idleTimeout
)
: PThread(5000, AutoDeleteThread),
m_idleTimeout(idleTimeout*1000), m_closed(false), m_job(NULL), m_id(0),
m_agent(agent)
{
// resume suspended thread (and run Main)
Resume();
}
Worker::~Worker()
{
PWaitAndSignal lock(m_jobMutex);
if (m_job) {
DEBUG_TEST(1, "JOB/tDestroying Worker " << m_id << " with active Job " << m_job->GetName());
delete m_job;
m_job = NULL;
}
DEBUG_TEST(5, "JOB/tWorker " << m_id << " destroyed");
}
void Worker::Main()
{
m_id = GetThreadId();
DEBUG_TEST(5, "JOB/tWorker " << m_id << " started ");
只要該worker沒有停止,就會檢測時候有Job提交到該Worker,如果有就執行之,
否則就睡覺去,等待Job的到來
while (!m_closed) {
bool timedout = false;
// wait for a new job or idle timeout expiration
if (m_job == NULL) {
timedout = !m_wakeupSync.Wait(m_idleTimeout);
if (timedout)
{ DEBUG_TEST(5, "JOB/tIdle timeout for Worker " << m_id);
}
}
// terminate this worker if closed explicitly or idle timeout expired
if (m_closed || (timedout && m_job == NULL)) {
程序處於空閒的狀態,好久沒有任務可以執行,先停止,回去休息一下,等忙的時候再由Agent調出來
執行Job
m_closed = true;
break;
}
if (m_job) {
DEBUG_TEST(5, "JOB/tStarting Job " << m_job->GetName()
<< " at Worker thread " << m_id
);
重點在這裏,調用Job的Run函數,執行某個Job具體的指令,以完成其提交的任務。
m_job->Run();
{
PWaitAndSignal lock(m_jobMutex);
delete m_job;
m_job = NULL;
}
m_agent->JobDone(this);
}
}
DEBUG_TEST(5, "JOB/tWorker " << m_id << " closed");
// remove this Worker from the list of workers
m_agent->Remove(this);
if (m_job)
{
DEBUG_TEST(1, "JOB/tActive Job " << m_job->GetName()
<< " left at closing Worker thread " << m_id
);
}
}
bool Worker::Exec(
/// Job to be executed
Job* job
)
{
// fast check if there is no job being executed
if( GetThreadId()== 0 )
{
DEBUG_TEST(0,"thread id is zeor "<<GetThreadId());
return false ;
}
if (m_job == 0 && !m_closed) {
PWaitAndSignal lock(m_jobMutex);
// check again there is no job being executed
if (m_job == 0 && !m_closed) {
m_job = job;
m_wakeupSync.Signal();
return true;
}
}
return false;
}
void Worker::Destroy()
{
// do not delete itself when the thread is stopped
SetNoAutoDelete();
m_jobMutex.Wait();
if (m_job)
m_job->Stop();
m_jobMutex.Signal();
m_closed = true;
m_wakeupSync.Signal();
DEBUG_TEST(5, "JOB/tWaiting for Worker thread " << m_id << " termination");
WaitForTermination();
/* 自我銷燬*/
delete this;
}
Agent::Agent() : Singleton<Agent>("Agent"), m_active(true)
{
}
Agent::~Agent()
{
DEBUG_TEST(5, "JOB/tDestroying active Workers for the Agent");
std::list<Worker*> workers;
#if PTRACING
int numIdleWorkers = -1;
int numBusyWorkers = -1;
#endif
{
// move all workers to the local list
PWaitAndSignal lock(m_wlistMutex);
m_active = false;
#if PTRACING
numIdleWorkers = m_idleWorkers.size();
numBusyWorkers = m_busyWorkers.size();
#endif
while (!m_busyWorkers.empty()) {
workers.push_front(m_busyWorkers.front());
m_busyWorkers.pop_front();
}
while (!m_idleWorkers.empty()) {
workers.push_front(m_idleWorkers.front());
m_idleWorkers.pop_front();
}
}
#if TEST_
DEBUG_TEST(5, "JOB/tWorker threads to cleanup: " << (numBusyWorkers+numIdleWorkers)
<< " total - " << numBusyWorkers << " busy, " << numIdleWorkers << " idle"
);
#endif
// destroy all workers
ForEachInContainer(workers, mem_vfun(&Worker::Destroy));
DEBUG_TEST(5, "JOB/tAgent and its Workers destroyed");
}
void Agent::Exec(
/// the job to be executed
Job* job
)
{
Worker* worker = NULL;
#if PTRACING
int numIdleWorkers = -1;
int numBusyWorkers = -1;
#endif
// pop the first idle worker and move it to the busy list
if (job) {
PWaitAndSignal lock(m_wlistMutex);
// delete the job if the Agent is being destroyed
if (!m_active) {
DEBUG_TEST(5, "JOB/tAgent did not accept Job " << job->GetName());
delete job;
job = NULL;
return;
}
/*如果有空閒的worker,從中其一個來執行worker*/
if (!m_idleWorkers.empty()) {
worker = m_idleWorkers.front();
m_idleWorkers.pop_front();
m_busyWorkers.push_front(worker);
#if PTRACING
numIdleWorkers = m_idleWorkers.size();
numBusyWorkers = m_busyWorkers.size();
#endif
}
} else
return;
bool destroyWorker = false;
// if no idle worker has been found, create a new one
// and put it on the list of busy workers
/* 如果沒有空閒的worker創建一個新的worker來執行job
並把worker加入忙隊列*/
if (worker == NULL) {
worker = new Worker(this);
PWaitAndSignal lock(m_wlistMutex);
if (m_active)
m_busyWorkers.push_front(worker);
else
destroyWorker = true;
#if PTRACING
numIdleWorkers = m_idleWorkers.size();
numBusyWorkers = m_busyWorkers.size();
#endif
}
// execute the job by the worker
// if worker is running the the worker id > 0 else == 0
/*提交job到worker 如果提交失敗,一般是worker 線程已經停止,
就刪除job,否則不能刪除job*/
if (!(m_active && worker->Exec(job))) {
// should not ever happen, but...
DEBUG_TEST(1,"can't execute the job,delete it "<<job->GetName());
delete job;
job = NULL;
PWaitAndSignal lock(m_wlistMutex);
m_busyWorkers.remove(worker);
if (m_active)
m_idleWorkers.push_front(worker);
else
destroyWorker = true;
#if PTRACING
numIdleWorkers = m_idleWorkers.size();
numBusyWorkers = m_busyWorkers.size();
#endif
}
#if PTRACING
PTRACE_IF(5, m_active, "JOB/tWorker threads: " << (numBusyWorkers+numIdleWorkers)
<< " total - " << numBusyWorkers << " busy, " << numIdleWorkers << " idle"
);
#endif
if (destroyWorker) {
DEBUG_TEST(5, "JOB/tAgent did not accept Job " << job->GetName());
worker->Destroy();
}
}
void Agent::Remove(
Worker* worker
)
{
#if PTRACING
int numIdleWorkers;
int numBusyWorkers;
{
#endif
PWaitAndSignal lock(m_wlistMutex);
// check both lists for the worker
m_idleWorkers.remove(worker);
m_busyWorkers.remove(worker);
#if PTRACING
numIdleWorkers = m_idleWorkers.size();
numBusyWorkers = m_busyWorkers.size();
}
PTRACE_IF(5, m_active, "JOB/tWorker threads: " << (numBusyWorkers+numIdleWorkers)
<< " total - " << numBusyWorkers << " busy, " << numIdleWorkers << " idle"
);
#endif
}
void Agent::JobDone(
/// the worker to be marked as idle
Worker* worker
)
{
#if PTRACING
int numIdleWorkers;
int numBusyWorkers;
{
#endif
PWaitAndSignal lock(m_wlistMutex);
m_busyWorkers.remove(worker);
if (m_active)
m_idleWorkers.push_front(worker);
#if PTRACING
numIdleWorkers = m_idleWorkers.size();
numBusyWorkers = m_busyWorkers.size();
}
PTRACE_IF(5, m_active, "JOB/tWorker threads: " << (numBusyWorkers+numIdleWorkers)
<< " total - " << numBusyWorkers << " busy, " << numIdleWorkers << " idle"
);
#endif
}
Task::~Task()
{
}
Job::~Job()
{
DEBUG_TEST(5, "JOB/tJob " << GetName() << " deleted");
}
void Job::Execute()
{
提交任務到代理,由代理調度執行
Agent::Instance()->Exec(this);
}
void Job::Stop()
{
}
void Job::StopAll()
{
停止整個程序的所有Job
delete Agent::Instance();
}
void Jobs::Run()
{
執行Jobs
while (m_current) {
m_current->Exec();
m_current = m_current->DoNext();
}
}
RegularJob::RegularJob() : m_stop(false)
{
}
void RegularJob::OnStart()
{
}
void RegularJob::OnStop()
{
}
void RegularJob::Run()
{
OnStart();
while (!m_stop)
Exec();
// lock to allow a member function that is calling Stop
// return before OnStop is called and the object is deleted
PWaitAndSignal lock(m_deletionPreventer);
OnStop();
}
void RegularJob::Stop()
{
// signal stop flag and wake up job thread, if it is in the waiting state
m_stop = true;
m_sync.Signal();
}