我正在研究如何让我们的团队了解并发性.开发人员陷入周围并发的最常见陷阱是什么?例如,在.Net中,关键字static
为许多并发问题打开了大门.
是否有其他设计模式不是线程安全的?
这里有很多很棒的答案很难选择一个作为公认的答案.请务必滚动浏览所有提示.
这个帖子已经有很多很好的答案和指针,但是我要补充一点.
不要依赖测试来查找比赛条件和死锁
假设您拥有所有良好的开发流程:每个组件的单元测试,每个夜间构建的冒烟测试,要求每个开发人员的更改在签入之前通过测试等.
所有这一切都很好,但它会导致一种态度"好吧,它通过了测试套件,因此它不能成为我代码中的错误." 在并发编程中不能很好地为你服务.实时并发错误非常难以重现.在失败之前,您可以运行一段具有竞争条件十亿次的代码.
您将不得不调整您的流程,以更加重视由您的最佳思想进行的代码审查.仅针对并发问题进行单独的代码审查并不是一个坏主意.
您将不得不更加重视使应用程序自我调试.也就是说,当您在测试实验室或客户的站点出现故障时,您需要确保捕获并记录足够的信息以便进行明确的事后检查,因为您能够在以下情况下重现错误报告的可能性您的便利性可以忽略不计.
您将不得不更加强调代码中的偏执健全性检查,以便尽可能地检测到故障,而不是50,000行代码.
偏执狂.非常偏执.
一种是竞争条件,它基本上假设一条代码将在另一条并发代码之前/之后运行.
还有死锁,即代码A等待代码B释放资源Y,而代码B等待A释放资源X.
我和朋友和同事一起教并发很多.以下是一些重大缺陷:
假设一个主要在许多线程中读取并且只写在一个线程中的变量不需要被锁定.(在Java中,这种情况可能导致读取线程永远不会看到新值.)
假设线程将以特定顺序运行.
假设线程将同时运行.
假设线程不会同时运行.
假设所有线程都会在任何一个线程结束之前前进.
我也看到:
thread_fork()
和之间的大混乱fork()
.
在一个线程中分配内存而free()
在另一个线程中分配d 时的混淆.
由于某些库是线程安全而某些库不是线程安全而导致的混淆.
人们使用自旋锁时应该使用睡眠和唤醒,或者选择,或者语言支持的任何阻止机制.
并发没有很多陷阱.
但是,同步对共享数据的访问非常棘手.
以下是编写共享数据同步代码的人应该能够回答的一些问题:
什么是InterlockedIncrement?
为什么InterlockedIncrement需要以汇编语言级别存在?
什么是读写重新排序?
什么是volatile关键字(在c ++中)以及何时需要使用它?
什么是同步层次结构?
什么是ABA问题?
什么是缓存一致性?
什么是记忆障碍?
"共享一切"并发性是一种极其漏洞的抽象.改为采用无共享消息传递.
最大的缺陷之一是首先使用并发.并发性增加了大量的设计/调试开销,因此您必须检查问题并查看它是否真的需要并发.
并发在某些领域肯定是不可避免的,但是当它可以避免时,请避免它.