shines77 / RingQueue

A lock-free(or spin-lock) Queue implemented by RingBuffer.
MIT License
124 stars 55 forks source link

感觉你并没有把他们的讨论看完,从最后的结论来看你并没把它的问题所在改对 #1

Closed guitaryang closed 3 years ago

shines77 commented 5 years ago

你想表达什么意思啊,如果你觉得有问题,你可以把你觉得有问题的地方描述出来。或者你觉得我没看完他们的讨论,是哪些地方我没看完,或者你觉得我哪里不对的地方,可以详细的指出来。其实你说的问题,我有点摸不着头脑。。

因为,,,其实,,,似乎,,,好像可能是你没完,我觉得。。。(不管怎么样,你要详细描述你的问题,不然我真不知道应该怎么回答。。)

guitaryang commented 5 years ago

好吧,我还以为这么久了,你不会再回复了。q3.h写的没有问题的。 image

shines77 commented 5 years ago

GitHub 几乎是每天都在用的,偶尔会看看消息之类的(有时候没留意),博客园是很少上了的。

我没有说 q3.h 是错的,的确在弱内存一致性的CPU上,加一个硬件内存屏障(hardware memory fence)就可以了。我的文章里也没有说他是错的,但是 q3.h 这种写法,第一,效率不够高,第二,是有可能会出现活锁(livelock)的情况的。具体可以参看 https://www.cnblogs.com/shines77/p/4200127.html 关于 push() 的最后一段。现在我知道是什么原因造成的了,这种情况也会在 Intel 的 DPDK 的 rte_ring 队列上出现,因为他们原理是相似的。

其实博客园上有一个朋友问了我关于 DPDK 的 rte_ring 队列的问题,消息我看了,一直忘记回复他,希望他能在这里看到。DPDK 的 rte_ring 队列的活锁问题跟 q3.h 是类似的。

shines77 commented 5 years ago

如果想用 q3.h 这种队列,可以参考一下 DPDK 的 rte_ring 队列,它写得比较成熟一点,毕竟是 Intel 出品。DPDK 是一套用于写用户态网卡驱动(不是内核态的网卡)的库。但是使用不当,的确是有可能会出现 livelock(活锁) 的现象。关于 DPDK 的 rte_ring 队列的介绍,可以百度一下。

shines77 commented 5 years ago

我把回复那位朋友的也贴在这里,可以参考一下:

不好意思,几个月前就看到了你的回复,一直都忘记回复你。

我百度了一下DPDK的rte_ring队列,其实写得不错,比 q3.h 完整很多,我没仔细看过其源码,但估计跟 q3.h 的原理是相似的。所以在当你的队列使用的线程数大于你的逻辑内核数(即包含超线程)时,并且你给你的线程绑定了CPU亲缘性的话,那么就必然会出现活锁(livelock)的现象。解决的办法是,使用了CPU亲缘性的话,就不要让两个线程绑定在同一个物理核心,即使没使用CPU亲缘性,也尽量不要这么做,虽然没有前者那么慢,但还是比正常的情况要慢的。

其实后者也已经出现了活锁现象,只不过由于没有绑定CPU亲缘性,操作系统还是有机会尝试来解决活锁的问题,但是,操作系统的调度策略是需要一定的时间才能奏效的,所以此时,队列就会比正常的情况慢很多。如果绑定了CPU亲缘性的话,那么操作系统也无法通过把线程调度到别的CPU上来有效的解决活锁问题,所以就会变得非常非常的慢。。。

由于 q3.h 的代码里使用了 _mm_pause() 这种指令,在面对支持超线程的CPU的时候,可以切换到同一个物理内核的其他的逻辑内核(超线程)上,我不知道DPDK的rte_ring队列是否使用了_mm_pause() 来切换超线程。如果没有使用的话,那么队列使用的线程数就不得超过你的物理内核数(即不包含超线程),否则是会比较慢的,如果同时还做了CPU亲缘性绑定,那么就会非常非常慢,即活锁(livelock)现象。

下面是我文章 https://www.cnblogs.com/shines77/p/4200127.html 里的原话:

q3.h 还有一个问题就是,有可能会活锁(livelock),虽然没有完全死锁(deadlock),但是 push() 和 pop() 执行得很慢很慢,超出常规的效率,原因还不太明白,有空再好好想想。出现这种情况的条件是(以下两种描述因为有点忘记了,如果说得不对我会及时纠正):如果不开CPU亲缘性的话,且当PUSH_CNT + POP_CNT 大于CPU的实际核心数的时候,会很慢;如果开启了CPU亲缘性的话,当PUSH_CNT + POP_CNT 大于CPU的实际核心数的时候,会非常慢,比前者还要慢。除了这些情况以外,执行效率还算正常。