【问题标题】:Threading Architecture Question C++ Message Passing线程架构问题 C++ 消息传递
【发布时间】:2011-03-21 07:50:23
【问题描述】:

简单的问题,我想。

我有一个线程响应用户通过 TCP 连接时调用的回调。如果我接受或拒绝登录,该回调需要一个答案。问题是我必须通过异步消息传递向安全服务器发送登录请求并等待响应。

处理此问题的最佳方法是什么?现在我有一些代码只是在回调测试中循环,以查看安全服务器是否发送了回复,当它进来时,我读取它并返回适当的布尔值。只是看起来有点恶心。

TIA

【问题讨论】:

  • 就像我在想可能是 Boost condition_variable 或类似的东西。
  • 我最近注意到许多问题几乎与此相同。这是某种课堂项目吗?只是好奇。

标签: c++ multithreading architecture


【解决方案1】:

首先,您需要一个包含监视器类的锁定库,该类能够:

  • 获取锁,保证互斥,即任何时候只有一个线程可以持有锁
  • sleep on the lock,即暂时释放锁,一直休眠直到可以重新获取锁
  • 锁上的信号,通知休眠线程它们应该唤醒并重新获取锁。只有在持有锁时才能在锁上发出信号。这意味着该信号永远不会立即产生唤醒其他线程的效果。通常,信号线程会发出信号,然后立即释放锁,从而使刚刚收到信号的线程唤醒。唤醒具有将阻塞调用返回到睡眠的效果,并重新获得锁。

因此,对于某些库提供的功能,您需要实现一个安全服务器代理,该代理使用异步安全服务器来实现同步服务。当在某个线程(表示为线程 1)中调用同步 authenticate() 函数时,应该会发生这种情况:

  1. 代理获取锁
  2. 代理向安全服务器发送请求消息
  3. 代理进入睡眠状态,等待结果,线程 1 现在被阻塞,锁可用
  4. 安全服务器计算结果
  5. 安全服务器向代理发送带有结果的消息
  6. 代理消息处理函数在线程 2 中被调用,线程 1 仍然被阻塞
  7. 代理在线程 2 中获取锁
  8. 代理从消息中检索结果并将其存储在成员变量中
  9. 代理在锁上发出信号,导致线程 1 在睡眠时阻塞试图唤醒,但它不能,因为线程 2 仍然持有锁(在 sleep() 函数内,线程 2 现在在调用获取锁)
  10. 代理消息处理程序释放其锁定
  11. 线程 1 中的 sleep 调用重新获取锁并返回
  12. 线程 1 中的同步函数立即释放其锁并返回结果

线程 1 重新获取锁只是为了立即释放它的最后一部分可能看起来毫无意义,但它很重要,因为这确保了消息处理程序在同步函数继续执行之前完成。

在伪代码中,它实际上看起来比你想象的要简单得多:

class SecutityProxy
{
public:
    SecutityProxy( SecurityServer& server ) : m_server(server)
    {}
    Result authenticate( username, password )
    {
        m_monitor.lock();
        m_server.send_message( username, password );
        m_monitor.sleep();
        m_monitor.unlock();
        return m_result;
    }
    void message_received( message )
    {
        m_monitor.lock();
        m_result = message;
        m_monitor->signal();
        m_monitor.unlock();
    }
private:
    SecurityServer& m_server;
    Monitor m_monitor;
    Result m_result;
};

请注意,此实现一次不能处理多个请求!为了处理多个并发请求,您需要能够存储多个结果。您还需要存储每个请求对应的线程的线程句柄。在消息处理程序中,您需要确定哪个线程正在阻塞任何给定的请求,然后只需在 signal() 调用中唤醒相关线程,锁定库必须支持这一点。

另请注意,强烈建议实施 RAII 类来处理监视器上的 lock() 和 unlock() 调用。

【讨论】:

    【解决方案2】:

    在发起登录检查的函数中,发送消息后请求检查某事。 Windows 事件可以工作,布尔标志和boost::condition_variable 或boost::unique_future 也可以。

    在从安全服务器接收响应消息的代码中,设置事件、未来或标志/条件变量。这将唤醒初始函数并允许它向初始调用者返回适当的响应。

    【讨论】:

      【解决方案3】:

      您可能会阻止对安全服务器的异步调用以有效地使其同步。

      【讨论】:

      • 是的,但是如何阻止,使用互斥锁,休眠并检查变量?对 SecSrv 的调用是异步的,所以一旦我调用,它会立即返回,我必须做一些明确的事情来阻止并等待返回消息。我真的在问一个我想几乎是风格的问题,最流畅的编码方式是什么?
      • 我无法阻塞异步调用,我发送一条消息并稍后在另一个线程中接收一条消息。
      • 我查看了此处的示例代码 (windows-tech.info/13/e64a22df23c19164.php),我没有看到任何特殊原因导致您的回调在返回之前无法阻止手动重置事件。
      猜你喜欢
      • 2012-08-02
      • 2011-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      • 1970-01-01
      • 2021-07-08
      相关资源
      最近更新 更多