【问题标题】:Design and Technical issue in Multi Threaded Application多线程应用程序中的设计和技术问题
【发布时间】:2011-05-20 11:10:45
【问题描述】:

我想讨论与多线程应用程序相关的设计和技术问题/挑战。

我遇到的问题
1.我遇到了多线程使用共享函数/变量导致应用程序崩溃的情况,所以在这种情况下需要适当的保护。
2. 状态机和多线程-

在深入研究多线程应用程序之前应该记住几点。 可能存在与 1. Memory 2. Handle 3. Socket 等相关的问题。

请在以下几点分享您的经验

  1. 在多线程应用程序中常犯的错误是什么
  2. 与多线程相关的任何具体问题。
  3. 我们应该通过值传递数据还是在线程函数中通过引用传递数据。

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    嗯,有这么多……

    1) 共享函数/过程——它们只是代码,除非代码自己修改,否则不会有问题。局部变量没有问题,因为每个线程都在一个单独的堆栈上调用,(几乎按照定义:)。任何其他数据都可能成为问题并且可能需要保护。多任务操作系统上 99.99% 的所有家庭 API 调用都是线程安全的,几乎按照定义。另一位发帖者已经警告过线程本地存储...

    2) 状态机。可能有点尴尬。您可以轻松锁定所有触发到 SM 中的事件,从而确保状态的完整性,但是在锁定 SM 时,您不能从 SM 内部进行阻塞调用,(可能看起来很明显,但我已经这样做了......一次: )。

    我偶尔只从一个线程运行状态机,将事件对象排队到它。这会将锁定移至输入队列,这意味着 SM 更易于调试。这也意味着运行 SM 的线程可以在内部 delta 队列上实现超时,因此它自己会触发对 delta 队列上的对象的超时调用,(经典示例:具有连接超时的 TCP 服务器套接字 - 数千个套接字对象,每个都需要一个独立超时)。

    3) '我们应该通过值传递数据还是通过线程函数中的引用传递数据。'。不知道你的意思,在这里。大多数操作系统允许在创建线程时传递一个指针 - 随心所欲地使用它。您可以向它传递一个它应该在工作完成时发出信号的事件或一个等待工作请求的队列对象。创建后,您需要某种形式的线程间通信来发送请求并获取结果,(除非您要使用直接的“读/写/waitForExit”机制 - AV/deadlock/noClose 生成器)。

    我通常使用简单的信号量/CS 生产者-消费者队列在工作线程之间发送/接收通信对象,并使用 PostMessage API 将它们发送到 UI 线程。除了队列中的锁定之外,我通常不需要更多锁定。您必须非常努力地基于消息传递来使线程系统死锁,并且线程池之类的事情变得微不足道-只需使 [no. CPU] 线程并将每个线程传递给相同的队列以等待。

    常见错误。请参阅其他许多海报,我会在其中添加:

    a) 直接读取/写入线程字段以传递参数并返回结果,(尤其是在 UI 线程和“工作”线程之间),即“创建挂起的线程,将参数加载到线程字段中,恢复线程,等待线程退出句柄,从线程字段读取结果,释放线程对象'。这会导致持续创建/终止/销毁线程导致性能下降,并且通常会迫使开发人员确保在退出应用程序时终止线程以防止关闭时出现 AV/216/217 异常。这可能非常棘手,在某些情况下是不可能的,因为一些 API 的阻塞无法解除阻塞。如果开发者停止这种讨厌的做法,应用关闭问题就会少得多。

    b) 尝试以程序方式构建多线程应用程序,例如。试图在 UI 事件处理程序中等待来自工作线程的结果。构建线程请求对象、使用参数加载它、将其排队到工作线程并退出事件处理程序要安全得多。线程可以获取对象、执行工作、将结果放回对象中,并且(无论如何,在 Windows 上)PostMessage 将对象返回。 UI 消息处理程序可以处理结果并处理对象(或回收、重用:)。这种方法意味着,由于 UI 和 worker 总是在不同的数据上操作,这些数据可以比它们都活得更久,所以没有锁定,并且(通常)不需要确保在关闭应用程序时释放工作线程,(与此相关的问题是传奇)。

    Rgds, 马丁

    【讨论】:

      【解决方案2】:

      人们在多线程应用程序中面临的最大问题是race conditionsdeadlocks,而不是使用某种形式的semaphores 来保护全局可访问的变量。

      【讨论】:

      • 我有一个问题!如果线程更新值,我们需要某种保护机制。不更新值但只读取它的线程呢?你认为这里也需要保护
      • 守卫被称为信号量或互斥量。即使您只读取变量,也可能会遇到问题。 en.wikipedia.org/wiki/Unrepeatable_reads
      • 有时Terminate/kill线程不起作用并返回false。那么如果需要在线程运行时关闭线程,如何确保线程顺利关闭。
      • 这是一个相当大的设计问题,您需要确保线程自行清理,但您还需要查看很多东西。我建议单独查看每一件事。
      【解决方案3】:

      您在使用线程锁时会遇到这些问题。 僵局 优先级反转 护航 “异步信号安全” 容错可用性 抢占容错 整体表现

      如果您想了解更高级的线程技术,可以查看无锁线程,其中许多线程在等待时处理相同的问题。

      【讨论】:

        【解决方案4】:

        由于缺乏适当的同步而导致的死锁、内存损坏(共享资源)、缓冲区溢出(甚至可能由于内存损坏而发生)、线程本地存储的不当使用是最常见的事情

        还取决于您用于实现线程的平台和技术。例如在 Microsoft Windows 中,如果您使用 MFC 对象,则多个 MFC 对象实际上无法跨线程共享,因为它们严重依赖线程本地存储(例如 CSocket、CWnd 类等)

        【讨论】:

          猜你喜欢
          • 2012-10-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-07
          • 1970-01-01
          • 1970-01-01
          • 2022-01-02
          相关资源
          最近更新 更多