首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >两个服务器的线程安全类实现

两个服务器的线程安全类实现
EN

Stack Overflow用户
提问于 2013-08-03 00:49:09
回答 1查看 82关注 0票数 0

我有一个有2个成员的类:

代码语言:javascript
复制
RequestController {
  public:
    SendRequest();  // called by multiple threads synchronously
  private:
    server primary;   // This is the primary server
    server backup;    // This is the back up server.
}

我的逻辑很简单:

在SendRequest()中,我想发送请求到主服务器,如果失败,我想发送到备份服务器,如果通过,我想交换主服务器和备份服务器。

问题来了:当我进行交换时,我必须锁定主线程和备份线程(这是多个线程不能同时执行的地方)。实际上,我需要确保在交换时,没有线程正在读取主服务器。如何以有效的方式编写这段代码?我不想锁定整个事情,因为在大多数情况下,主服务器都可以工作,不需要锁定。

我认为这个问题通常是与语言无关的。不管怎样,我用C++标记了它。

EN

回答 1

Stack Overflow用户

发布于 2013-08-03 01:14:18

让我们假设服务器需要花费一些不可忽略的时间来处理请求。然后,如果请求来得足够快,就会出现第二次调用SendRequest的情况,而它正在等待其中一个服务器处理上一个请求。

作为一个设计师,你有两个选择。

  1. 如果服务器同时处理多个请求是可以的,那么您什么也不做。
  2. 如果服务器一次只能处理一个请求,则需要对代码执行某种类型的同步。

在第二种情况下,由于您已经锁定了服务器,因此您可以交换它们,而不会产生任何后果。

对于第一种情况,为什么不执行以下操作:

代码语言:javascript
复制
std::mutex my_mutex;
...
// Select the server
server* selected = NULL;
my_mutex.lock();
  selected = &primary;
my_mutex.unlock();

// Let the selected server process the message.
bool success = selected->process();

// If there was a primary failure, see if we can try the backup.
if (!success) {
  my_mutex.lock();
  if (selected == &primary) {
    selected = &backup;
  }
  my_mutex.unlock();

  // Now try again
  success = selected->process();

  // If the backup was used successfully, swap the primary and backup.
  if (success) {
    my_mutex.lock();
    if (selected == &backup) {
      backup = primary;
      primary = selected;
    }
    my_mutex.unlock();    
  }
}

但这可能会有一些问题。例如,假设主节点在第一条消息上失败,但在其余消息上成功。如果SendRequest()被3个不同的线程同时调用,那么你可能会得到以下结果:

备份主线程1-使用primary

  • Thread发送2-使用primary

  • Thread发送3-使用primary

  • Thread 1发送-失败,使用backup

  • Thread发送2-主succeeds

  • Thread 1-备份succeeds

  • Thread 1-交换主要和backup

  • Thread 3-旧的主要(新备份) succeeds

  • Thread 3-交换主要和备份

如果消息持续以足够快的速度到来,则可以保持这种状态,在这种状态下,您可以不断地交换主和备份。这种情况将在没有挂起消息的瞬间解决,然后设置主和备份,直到再次出现故障。

也许更好的方法是永远不要交换,而是有一个更好的选择方法。例如:

代码语言:javascript
复制
...
// Select the server
server* selected = NULL;
selected = &primary;
if (!primary.last_message_successful) {
  // The most recent attempt made with primary was a failure.
  if (backup.last_message_successful) {
    // The backup is thought to be functioning.
    selected = &backup;
  }
}

// Let the selected server process the message.
// If successful, process() will set the last_message_successful boolean.
bool success = selected->process();

// If there was a failure, try the other one.
if (!success) {
  if (&primary == selected) {
    selected = &backup;
  } else {
    selected = &primary;
  }
}

// Try again with the other one.
selected->process();

在本例中,锁不是必需的。主节点将一直使用,直到出现故障。则将使用备份。如果同时处理其他消息,可能会导致主消息再次可用,在这种情况下,将使用主消息。否则,备份将一直使用,直到失败。如果两者都失败,则会同时尝试它们,首先是主服务器,然后是备份服务器。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18022219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档