"这篇文档是谷正阳同学的并行与分布式计算作业,主要探讨了数据竞争和不可重入函数的检测与分析。通过使用ThreadSanitizer和perf工具,对多线程程序进行了性能和安全性评估。"
在并行与分布式计算中,正确处理并发问题是至关重要的。本作业涉及两个关键概念:数据级并行和线程级并行,以及如何通过工具检测和避免潜在的问题。
首先,数据竞争是多线程编程中的常见问题,指多个线程同时访问和修改同一块数据,可能导致不可预测的结果。谷正阳同学使用ThreadSanitizer(tsan)工具对三个多线程程序进行了检查。tsan是一个动态运行时系统,用于检测数据竞争和其他线程安全问题。经过分析,列向量内元素求和和列向量求和的程序未发现数据竞争,而分治算法求矩阵乘积的多线程版本则存在数据竞争。为了解决这个问题,他缩小了矩阵规模到2*2,并采用了自旋锁(spinlock)来防止数据竞争。自旋锁是一种原地等待的锁机制,当一个线程无法立即获得锁时,它会持续循环检查锁的状态,而不是挂起自己,适合于锁的持有时间较短的情况。
其次,不可重入函数是指在调用过程中不能被中断并再次调用的函数。这些函数可能会导致死锁或其他并发问题。谷正阳编写了一个名为tiny_race.c的简单程序,模拟了使用全局变量、调用标准IO函数`getchar`和使用`malloc`等可能引起不可重入问题的场景。不可重入函数在多线程环境下需特别注意,因为它们可能会导致资源管理的问题,例如内存分配失败或数据破坏。
在性能分析方面,使用perf工具对有锁和无锁的程序进行了比较。perf是一款强大的性能分析工具,可以深入操作系统内核,分析程序的性能瓶颈。结果显示,使用锁的多线程程序效率较低,接近于单线程程序的效率。这可能是由于数据规模较小,锁的开销对整体性能影响较大。然而,由于数据竞争不影响最终结果,这表明在这种情况下,尽管效率降低,但结果的正确性得以保持。
该作业展示了如何利用现代化的工具如ThreadSanitizer和perf来诊断和优化多线程程序,以及理解并发编程中数据竞争和不可重入函数的影响。通过这样的实践,学生可以更好地掌握并行计算中的挑战和解决策略,这对于理解和编写高效、可靠的并发代码至关重要。