GNUGK(2.2.3)源代碼分析之線程池結構

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();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章