代码之家  ›  专栏  ›  技术社区  ›  Sudhanshu

复杂多线程代码中的安全网?

  •  4
  • Sudhanshu  · 技术社区  · 15 年前

    作为一个刚在一个项目中完成了数千行复杂的多线程“C”代码的开发人员,并且将来会有几个不熟悉该代码的开发人员对其进行增强、修改等,我想知道你们试图加入哪种安全网?作为一个例子,我可以这样做:

    1. 定义用于受锁定保护的访问器宏 结构成员,声明 保持相应的锁。这个 明确表示这些成员 对不熟悉此代码的任何人都有锁保护。
    2. 应具有的功能 有人拿着旋转锁打电话, 断言旋转锁被持有。

    您在编写的多线程代码中加入了什么样的安全网?
    当其他开发人员修改此类代码时,您遇到了什么样的问题?
    你在这些代码中加入了什么样的调试工具?

    谢谢你的评论。

    3 回复  |  直到 15 年前
        1
  •  6
  •   Mark oskin    15 年前

    在我们的产品中,我们做了很多事情(一个旨在帮助您在应用程序中发现并发错误的管理程序),这些事情通常更有用。注意,我们在代码本身中执行这些操作(因为它是一个高度并发的软件部分),并且无论您是否在编写并发代码,其中的一些操作都是有用的。

    • 像您一样,我们有能力断言(lock-hold(…)并使用它。

    • 我们也(因为我们有自己的调度程序)可以断言(single_threaded())用于那些我们不依赖于系统中其他线程处于活动状态的(罕见)情况。

    • 从一个线程到另一个线程的内存损坏是非常常见的(而且很难调试),所以我们做了两件事来解决这个问题:散布在整个线程堆栈中的是一些神奇的cookie。我们定期(在get_thread_id()中)调用一个“validate_thread_stack()”函数来检查这些cookie以确保堆栈没有损坏。

    • 我们的malloc会在malloc内存块前后粘贴魔法饼干,并免费检查这些饼干。如果有人超过了他们的数据,这些可以用来尽早发现腐败。

    • 在free()上,我们在内存上爆炸一个众所周知的模式(在我们的例子中是0xdddd…)。这很好地腐蚀了任何其他有一个悬空指针留在那个记忆区域的人。

    • 在线程堆栈的底部附近有一个保护页(未映射到地址空间的内存页)。如果线程超出了它的堆栈,我们会通过页面错误捕获它并将其放入调试器中。

    • 我们的锁有人目击。签出freebsd锁见证代码。就像那样,但自制的。基本上,见证代码是一种轻量级的检测方法 潜在的 通过查看锁采集图中的循环来死锁。

    • 我们的锁也使用记录获取和释放的文件/行数的访问器进行包装。对于双重解锁或双重锁定,您可以获得有关错误的非常好的调试信息。

    • 我们的锁也是仿形的。一旦代码正常工作,你就希望它正常工作。我们跟踪通常的事情,比如多少次收购,收购需要多长时间。

    • 在我们的系统中,我们期望锁不会被争用(我们以这种方式仔细设计了代码)。因此,如果您在我们的系统中等待一个自旋锁的时间超过一两秒钟,您将被放入调试器,因为它很可能不是一件好事。

    • 我们要原子更新的变量被包装在C结构中。原因是为了防止在混合了良好使用的地方出现草率的代码:原子增量(&var);以及错误使用var++。我们很难编写后一种代码。

    • “volatile”在我们的代码库中是被禁止的,因为它由编译器模糊地实现。尝试拼凑同步是一种糟糕的方法。

    • 当然,代码审查。如果您不能向同事解释并发性假设和锁定规则,那么代码肯定有问题:—)

        2
  •  2
  •   Hassan Syed    15 年前

    使所有的事情都非常明显,以便其他开发人员在单独查看代码的子部分时不会错过同步范围。

    例如:不要在跨多个文件的代码中持有锁。

        3
  •  1
  •   Steve Emmerson    15 年前

    似乎您已经回答了自己的问题:在代码中放入大量断言。它们将告诉其他开发人员必须具备哪些不变量和前提条件。