浅析领导者跟随者线程模型

来源:互联网 发布:刘美麟因为爱情网络 编辑:程序博客网 时间:2024/06/06 18:41

领导者跟随者线程模型是一种经典的线程模型。首先我们来看看什么是领导者和跟随者线程模型,这种模型是怎么定义的。下面给出定义:在该模型中,存在一个领导者线程,处理主要的业务逻辑,比如从socket上读取数据。主要的业务逻辑处理完成后,领导者线程将降级,并且负责选择新的领导者线程。当降级的线程把剩余的业务逻辑完成后,将自动回归线程池,变为跟随者。等待下一次被领导者选中。

 

 

    在ACE(Adaptive Communication Environment)中,提供了一种实现,下面对这种实现进行源码级的分析。

我们针对主要逻辑进行分析,看看线程池是如何对领导者和跟随者进行切换的。先来看看线程池的线程方法的实现:
int LF_ThreadPool::svc (void)
{
  ACE_TRACE (ACE_TEXT ("LF_ThreadPool::svc"));
  while (!done ())
  {
      任何一个跟随者线程都会阻塞在这个方法上,直到自己有机会变成领导者,才会解除阻塞,该方法会放在后面进行分析。
      become_leader ();

      这段代码很简单,当跟随者线程变成领导者后,负责处理主要逻辑,就是从队列里获取消息。如果取消息失败,新的领导者将被选取,该线程退化为跟随者。
      ACE_Message_Block *mb = 0;
      ACE_Time_Value tv (LONG_TIME);
      tv += ACE_OS::gettimeofday ();

      // Get a message, elect new leader, then process message.
      if (this->getq (mb, &tv) < 0)
        {
          if (elect_new_leader () == 0)
            break;
          continue;
        }
      在领导者线程处理完主要逻辑后,负责选取新的领导者。该方法也将在后面作出详细分析。
      elect_new_leader ();
      领导者线程降级,处理生下来的业务逻辑,处理完之后,变成跟随者线程。
      process_message (mb);
  }

  return 0;
}

 

接下来,我们会对前面涉及的两个主要方法作出分析。
int LF_ThreadPool::become_leader (void)
{
  ACE_TRACE (ACE_TEXT ("LF_ThreadPool::become_leader"));

  ACE_GUARD_RETURN
    (ACE_Thread_Mutex, leader_mon, this->leader_lock_, -1);
  if (leader_active ())
{
  创建一个新的跟随者对象,里面包含一个条件变量,用于同步。
      Follower *fw = make_follower ();
      {
        如果存在领导者,跟随者线程暂时不能升级为领导者,所以先在这里等待机会。
        while (leader_active ())
          fw->wait ();
      }
      一旦跟随者有机会升级为领导者,将删除这个用于同步的领导者对象。防止内存泄露,此时已经不再需要这个对象了。
      delete fw;
    }

  ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t) Becoming the leader/n")));

  最后将自己升级为领导者
  leader_active (ACE_Thread::self ());
  return 0;
}

 

下面一个方法是领导者的选取方法。先介绍创建跟随者的方法。

这个方法很简单,从堆中申请一个跟随者对象,然后放入队列即可,采用了生产者和消费者模式。
Follower* LF_ThreadPool::make_follower (void)
{
  ACE_TRACE (ACE_TEXT ("LF_ThreadPool::make_follower"));

  ACE_GUARD_RETURN
    (ACE_Thread_Mutex, follower_mon, this->followers_lock_, 0);
  Follower *fw;
  ACE_NEW_RETURN (fw, Follower (this->leader_lock_), 0);
  this->followers_.enqueue_tail (fw);
  return fw;
}

 

接下来介绍主要的方法
int LF_ThreadPool::elect_new_leader (void)
{
  ACE_TRACE (ACE_TEXT ("LF_ThreadPool::elect_new_leader"));

  ACE_GUARD_RETURN
    (ACE_Thread_Mutex, leader_mon, this->leader_lock_, -1);
  leader_active (0);

  首先判断队列是否为空,如果为空,表示已经没有空闲资源在线程池中,这里可以优化一下,采用自适应的方式创建回收线程池中的线程。
  if (!followers_.is_empty ())
    {
      ACE_GUARD_RETURN (ACE_Thread_Mutex,
                        follower_mon,
                        this->followers_lock_,
                        -1);
      从队列中获取一个跟随者
      Follower *fw;
      if (this->followers_.dequeue_head (fw) != 0)
        return -1;
      ACE_DEBUG ((LM_DEBUG,
                  ACE_TEXT ("(%t) Resigning and Electing %d/n"),
                  fw->owner ()));
      通知该跟随者,目前你有机会变成领导者啦!恭喜恭喜……
      return (fw->signal () == 0) ? 0 : -1;
    }
  else
    {
      ACE_DEBUG
        ((LM_ERROR, ACE_TEXT ("(%t) Oops no followers left/n")));
      return -1;
    }
}

 

 

总结:
利用该线程模型,可以用在网络应用程序开发中,领导者负责从socket上读取数据,这个作为领导者的主要逻辑,之后让出领导者的权限,数据的处理作为该线程成为跟随者线程前应该处理的逻辑。线程池可以设计成自适应的,池中线程的数量可以根据当时的业务负载自动调整。


0 0
原创粉丝点击