【问题标题】:Network Multithreading网络多线程
【发布时间】:2010-09-13 15:45:08
【问题描述】:

我正在编写一个在线游戏有两个原因,一个是让自己熟悉实时环境中的服务器/客户端请求(而不是像典型的网络浏览器,它不是实时的),以及真正让我的手湿透在那个区域,所以我可以着手实际设计一个。

任何人,我都是用 C++ 做的,我一直在使用 winsock 来处理我的基本网络测试。我显然想使用帧限制器并在某个时候进行 3D 和所有这些,我的主要问题是当我执行 send() 或 receive() 时,程序会在那里闲置并等待响应。即使是最好的互联网连接,这也可能导致 8 fps。

所以对我来说显而易见的解决方案是将网络代码从主进程中取出并在自己的线程中启动它。理想情况下,我会在我的主进程中调用“发送”,它将向网络线程传递一个指向消息的指针,然后定期(每帧)检查网络线程是否已收到回复,或超时,或什么你。在一个完美的世界中,我实际上会同时运行 2 个或更多网络线程,这样我就可以说运行一个聊天窗口并在后台下载一件盔甲,同时仍然允许玩家一次到处跑。

我的大部分问题是这对我来说是新事物。我了解线程的概念,但我可以看到一些严重的问题,例如如果两个线程尝试同时读取/写入相同的内存地址会发生什么,等等。我知道已经有处理此类事情的方法,因此我正在寻找有关实现此类事情的最佳方法的建议。基本上,我需要线程 A 能够通过发送数据块启动线程 B 中的进程,轮询线程 B 的状态,然后接收回复,也作为数据块,理想情况下不会发生任何重大崩溃。 ^_^ 稍后我会担心这些数据实际包含什么以及如何处理丢弃的数据包等,我只需要先完成这些。

感谢任何帮助/建议。

PS:刚刚想到这一点,可能会使问题更简单。有没有办法使用 Windows 事件处理系统对我有利?比如,是否有可能让线程 A 在某处初始化数据,然后在线程 B 中触发一个事件以让它获取数据,反之亦然,让线程 B 告诉线程 A 它已经完成?这可能会解决我的很多问题,因为我真的不需要两个线程都能够同时处理数据,更多的是接力棒。我只是不知道这是否可能在两个不同的线程之间。 (我知道一个线程可以为事件处理程序创建自己的消息。)

【问题讨论】:

    标签: c++ multithreading networking


    【解决方案1】:

    最简单的事情

    对你来说,只需调用 Windows API QueueUserWorkItem。您只需指定线程将执行的函数以及传递给它的输入。将自动为您创建一个线程池并在其中执行作业。将在需要时创建新线程。

    http://msdn.microsoft.com/en-us/library/ms684957(VS.85).aspx

    更多控制

    您可以使用另一组 API 进行更详细的控制,这些 API 可以再次为您管理线程池 -

    http://msdn.microsoft.com/en-us/library/ms686980(VS.85).aspx

    自己动手

    如果你想控制你的线程创建和池管理的所有方面,你必须自己创建线程,决定它们应该如何结束,创建多少等(beginthreadex 是你应该用来创建线程的 api . 如果你使用 MFC 你应该使用 AfxBeginThread 函数)。

    向工作线程发送作业 - Io 完成端口

    在这种情况下,您还必须担心如何传达您的工作 - 我建议 IoCOmpletionPorts 这样做。这是我目前所知道的为此目的而设计的最具可扩展性的通知机制。它还有一个额外的优势,它是在内核中实现的,因此您可以避免在决定自己处理某些东西时遇到的各种死锁情况。

    本文将向您展示如何使用代码示例 -

    http://blogs.msdn.com/larryosterman/archive/2004/03/29/101329.aspx

    回信 - Windows 消息

    您可以使用 Windows 消息将状态传达回您的父线程,因为它无论如何都在等待消息。使用 PostMessage 函数来执行此操作。 (并检查错误)

    ps : 你也可以将需要发送的数据分配到一个专用指针上,然后工作线程可以在发送后负责删除它。这样您也可以避免返回指针流量。

    【讨论】:

    • 非Windows机器也有解决方案吗?
    【解决方案2】:

    BlodBath 关于非阻塞套接字的建议可能是正确的方法。

    如果您想避免使用多线程方法,那么您可以研究在套接字上设置重叠 I/O 的使用。当您进行传输或接收时,它们不会阻塞,但有额外的好处,让您可以选择在单个事件循环中等待多个事件。当您的传输完成后,您将收到一个事件。 (详情请见this

    这与多线程方法并不矛盾,因此您可以选择稍后改变主意。 ;-)

    关于多线程应用的设计。最好的办法是计算出所有你想要提醒的外部活动。例如,到目前为止,在您的问题中,您已经列出了网络传输、网络接收和用户活动。 根据您将要处理的并发连接的数量,您可能会发现在概念上每个套接字都有一个线程(假设套接字数量很少)在概念上更简单,其中每个线程负责该套接字的所有处理.

    然后您可以按照 RC 的建议在您的线程之间实现某种形式的消息传递系统。 安排您的系统,以便在将消息发送到特定线程时也发送事件。然后可以将您的线程发送到睡眠状态,等待其中一个事件。 (以及任何其他刺激 - 如套接字事件、用户事件等)

    你说得对,你需要小心多个线程试图访问同一块内存的情况。互斥量和信号量是在那里使用的东西。

    还要注意您的 gui 在多线程方面的限制。 可以在in this question 找到有关该主题的一些讨论。 但简化版是大多数(Windows 就是其中之一)GUI 不允许多个线程同时执行 GUI 操作。为了解决这个问题,您可以在应用程序中使用消息泵,通过向您的 gui 线程发送自定义消息来让 it 执行 gui 操作。

    【讨论】:

      【解决方案3】:

      我建议查看非阻塞套接字以进行快速修复。使用非阻塞套接字 send() 和 recv() 不会阻塞,使用 select() 函数可以在每一帧获取任何等待数据。

      【讨论】:

        【解决方案4】:

        将其视为producer-consumer problem:接收时,您的网络通信线程是生产者,而 UI 线程是消费者。发送时,正好相反。实现一个简单的缓冲区类,它为您提供 push 和 pop 之类的方法(pop 对于网络线程应该是阻塞的,而对于 UI 线程应该是非阻塞的)。

        比起使用 Windows 事件系统,我更喜欢更便携的东西,例如Boost condition variables

        【讨论】:

          【解决方案5】:

          我不编写游戏代码,但我使用的系统类似于 pukku 建议的系统。如果您有这样的需要,它非常适合做一些事情,比如让缓冲区优先处理要处理的消息。

          我认为它们是每个线程的邮箱。你想发送一个数据包?让 ProcessThread 创建一个带有有效负载的“线程消息”以通过网络传输并将其“发送”到 NetworkThread(即,将其推送到 NetworkThread 的队列/邮箱中并发送 NetworkThread 的条件变量信号,以便他醒来并把它拉下来)。当 NetworkThread 收到响应后,将其打包成一个线程消息,并以同样的方式发送回 ProcessThread。不同之处在于 ProcessThread 不会在条件变量上被阻塞,只是在您想要检查响应时轮询 mailbox.empty()。

          您可能希望直接推送和弹出,但对于较大的项目,更方便的方法是在 ThreadMsg 基类中实现 toThreadName、fromThreadName 方案,以及线程向其注册邮箱的 Post Office。然后邮局有一个 send(ThreadMsg*);根据 to 和 from 获取/推送消息到适当邮箱的函数。邮箱(缓冲区/队列类)包含 ThreadMsg* = receiveMessage(),基本上将其从底层队列中弹出。

          根据您的需要,您可以让 ThreadMsg 包含一个虚函数 process(..),它可以在派生类中被相应地覆盖,或者只拥有一个普通的 ThreadMessage 类,其中包含一个 to、from 成员和一个 getPayload() 函数取回原始数据,直接在ProcessThread中处理。

          希望这会有所帮助。

          【讨论】:

            【解决方案6】:

            您可能感兴趣的一些主题:

            • 互斥锁:互斥锁允许您仅锁定一个线程对特定资源的访问

            • 信号量:一种确定某个资源仍有多少用户(=多少线程正在访问它)以及线程访问资源的方法。互斥锁是信号量的一种特殊情况。

            • 临界区:一段受互斥锁保护的代码(街道只有一条车道),一次只能由一个线程运行。

            • 消息队列:一种在集中队列中分发消息的方式

            • 进程间通信 (IPC) - 一种线程和进程通过命名管道、共享内存和许多其他方式相互通信的方式(它更多的是一个概念而不是特殊技术)

            所有粗体字的主题都可以在搜索引擎上轻松查找。

            【讨论】:

              猜你喜欢
              • 2016-03-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-02-10
              相关资源
              最近更新 更多