我发现了下列不同类型的同步机制,并且每种机制都有锁定、解锁、测试锁等多个功能。
- GCC原子操作 - Futexes - 互斥锁 - 自旋锁 - 序列锁 - RCU锁 - 条件变量 - 信号量
我的当前(虽然可能存在缺陷)理解如下:
- 信号量是跨进程的,在文件系统中涉及(我认为是虚拟的),速度可能最慢。 - Futexes 可能是互斥锁、自旋锁、序列锁和RCU锁所使用的基本锁定机制。它们可能比基于它们的锁定机制更快。 - 自旋锁不阻塞,因此避免了上下文切换。但它们以耗尽CPU周期(旋转)来避免上下文切换。它们应仅在多处理器系统上使用,原因是显而易见的。永远不要在自旋锁中休眠。 - 序列锁告诉您什么时候完成工作,如果写入器更改了基于其数据的工作,则必须返回并重复该工作。 - 原子操作是最快的同步调用,并且可能在上述所有锁定机制中使用。您不想在共享数据中使用所有字段的原子操作。当您访问多个数据字段时,应使用锁(互斥锁、Futex、自旋锁、序列锁、RCU)或单个原子操作来对锁标志进行操作。
我的问题如下:
我的假设是否正确?
有人知道各种选项的cpu周期成本吗?我正在为应用程序添加并行性,以便在运行更少的应用程序实例的代价下获得更好的响应时间。性能是最重要的考虑因素。我不想通过上下文切换、旋转或大量额外的cpu周期来读写共享内存来消耗cpu。我绝对关心消耗的cpu周期数。
锁中哪些可以防止调度程序或中断线程...还是我只是个白痴,所有同步机制都这样做。防止哪些种类的中断?我可以阻止所有线程或仅阻止锁定线程的CPU上的线程?这个问题源于我担心打断持有锁的线程,该线程持有非常常用的函数。我预计调度程序可能会安排任意数量的其他工作线程,这些线程可能会遇到此函数,然后阻塞,因为它被锁定了。大量的上下文切换将浪费,直到具有锁的线程重新安排并完成。我可以重新编写此函数以最小化锁定时间,但仍然如此常被调用,我希望使用一个可以防止中断的锁...跨所有处理器。
我正在编写用户代码...所以我得到的是软件中断,而不是硬件中断...对吗?我应该避开任何带有“irq”单词的函数(旋转/序列锁)。
哪些锁是用于编写内核或驱动程序代码的,哪些是用于用户模式的?
有人认为使用原子操作让多个线程通过链接列表是疯狂的吗?我考虑原子地将当前项目指针更改为列表中的下一个项目。如果尝试成功,则线程可以安全地使用当前项目指向的数据,然后将其他线程移动到列表上。
futexes?有没有使用它们而不是互斥锁的理由?
是否有比使用条件来使线程在没有工作时睡眠更好的方法?
在使用gcc原子操作时,特别是test_and_set时,是否可以通过先进行非原子测试,然后使用test_and_set进行确认来获得性能提升?我知道这将是特定情况,因此这里是情况。有大量的工作项,例如数千个。每个工作项都有一个初始化为0的标志。当线程具有独占访问工作项时,该标志将为1。将有大量的工作线程。任何时候线程正在寻找工作时,它们可以进行非原子测试以获取1。如果他们读取了一个1,我们就能确定工作不可用。如果他们读取0,则需要执行原子test_and_set进行确认。因此,如果原子test_and_set是500个cpu周期,因为它禁用流水线,导致cpu通信和L2缓存刷新/填充....而简单测试仅需1个周期....那么只要在遇到已经完成的工作项方面,我有更好的500:1比率....这将是一个胜利。