免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
1234
最近访问板块 发新帖
楼主: ydfgic

[C] 【最终版 & 总结】自实现自旋锁 与 mutex,spinlock比较(结果令人吃惊) [复制链接]

论坛徽章:
1
申猴
日期:2014-02-11 14:50:31
发表于 2011-07-30 14:11 |显示全部楼层
忍不住说几句。

1、测试到0.???s级别的时间,没代表性。系统一次调度都可能是这个时间。你能保证每次测试,系统都处于相同的环境?
2、怎么没人注意“starwing83 (小翼)”说的。系统有几个cpu,编译环境如何,cache又如何?
3、现在的mutex是改良的了,如果锁是空闲的,线程获得此锁是不需要陷入内核态的

总之,我觉得这样的测试不具备一般性

论坛徽章:
0
发表于 2011-07-30 15:54 |显示全部楼层
忍不住说几句。

1、测试到0.???s级别的时间,没代表性。系统一次调度都可能是这个时间。你能保证每次测试 ...
chenzhanyiczy 发表于 2011-07-30 14:11



    1.因为测试代码我修改了根据输入参数选择不同的实现,所以每次测试都是连续完成的,而且都是测试至少三次以上,贴出来的也是平均值。
2 环境我1楼给出了
uname -a
Linux bsd02 2.6.35.9 #1 SMP Tue Jan 11 02:09:50 EST 2011 x86_64 GNU/Linux
双核 Pentium(R) Dual-Core  CPU      E5400  @ 2.70GHz
只有一台服务器,这个没法
3.我知道 mutex是优化过了的,如果没有竞争是不用进内核态的。这个实现没法取代mutex,因为如果是很长时间的加锁还是得用mutex,这个实现我想应该是在某些情况下取代phread_spinlock_t,因为它比较轻量级。
我贴出来的都是20个线程竞争,这个应该是比较“忙”的系统了。同时我也测试了10,5,2个线程的情况,发现:
这个实现对线程数不敏感,也就是上述的加锁的次数不变,时间也总是那个数,很稳定。
但是mutex在线程减少的情况下,还是保持1.4s的统计。phread_spinlock_t 倒是在线程数减少情况下,时间是递减,最后如果是2线程,结果是0.4~0.5s

论坛徽章:
0
发表于 2011-07-31 17:10 |显示全部楼层
楼主能否分析下pthread_spinlock_t的实现,与你的实现的
差别。会不会pthread_spinlock_t考虑了更多的情况?关注中。

论坛徽章:
0
发表于 2011-08-01 08:55 |显示全部楼层
回复 33# peidright


  pthread_spinlock_t的实现我想是考虑很多因素的吧,至少它要做到跨平台更好,还有功能更多一点,规范的接口。其实我的实现中调用的那个cas函数是GCC内建函数,也应该是跨平台的(*nix通用)。但是我因为不断的调整,最后的版本是个介于spinlock和mutex之间的产物,它不停的test是否能得到控制权(也就是所谓的锁),如果失败就放弃cpu时间片,这个和spinlock的理念截然相反。 适用的场合我想也是那种处于spinlock和mutex之间的选择,就是加锁不长不短,可能我会将这个用于我自己实现的无锁的list,stack这类基础结构中,和保护短暂加锁的情况。

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
发表于 2011-08-01 14:25 |显示全部楼层
不错, 前不久实现了一个类似的,  但很显然性能低些, 主要是不知道 __sync_bool_compare_and_swap() 这个函数, 呵呵。
另外, 楼主似乎不必使用volatile变量吧, 因为while循环中传入的本来就是指针, 即便cache, cache 的也是指针本身而不是指向的值。

static inline void lock(int* lk){
    int n;
LABEL:
    n = __sync_add_and_fetch(lk, 1);
    if(n != 1){
        __sync_sub_and_fetch(lk, 1);
        sched_yield();
        goto LABEL;
    }
}

static inline int try_lock(int* lk){
    int n;
LABEL:
    n = __sync_add_and_fetch(lk, 1);
    if(n != 1){
        __sync_sub_and_fetch(lk, 1);
        return -1;
    }
    return 0;
}



static inline void unlock(int* lk){
    __sync_sub_and_fetch(lk, 1);
}

论坛徽章:
0
发表于 2011-08-01 19:09 |显示全部楼层
回复 35# zylthinking
    确实是没必要,__sync_bool_compare_and_swap() 本身有内存屏障会同步各个cache的内存冲突,volatile 修饰实际也只是告诉编译器不要做过分的优化。好像是说加了后,编译器优化时候不会改变代码次序,并且读和写的时候直接是内存而不是cache。看你的代码也是同样的思想,想打到更好的细粒度加锁效率。呵呵

论坛徽章:
0
发表于 2013-11-17 21:56 |显示全部楼层
没有处理多处理器之间的高速缓存同步,这个代码应该没法用。

论坛徽章:
0
发表于 2015-04-09 14:12 |显示全部楼层
回复 1# ydfgic
【最终版 & 总结】自实现自旋锁 与 mutex,spinlock比较(结果令人吃惊)看到这个文章想和你讨论一下,可以加一下我QQ吗?谢谢 314462545

   

论坛徽章:
0
发表于 2019-06-06 15:32 |显示全部楼层
可以看下linux自旋锁的实现,还是比较巧妙的

论坛徽章:
0
发表于 2019-08-30 11:57 |显示全部楼层
楼主,你的实现,释放锁有可能出现正确性问题。
volatile关键字,并不能保证写后面的读操作跨越过来。
要用编译器栅障提示编译器:不能将后面的操作跨越过这条语句。
编译器栅障只是告诉编译器的标志,不会被编译成代码,在GCC:
__asm__ __volatile__("":::"memory")

MS为 _ReadWriteBarrier()

PS:编译器栅障不同于内存栅障。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

ITPUB技术栈

ITPUB技术栈:http://z.itpub.net/
ITPUB技术栈是由ITPUB社区打造的垂直于IT领域的知识交流平台,在这里,你既可以是创作者也可以是消费者。如果你的IT生涯丰富多彩,喷薄的个人价值尽可在小栈内体现;如果你渴望找到志同道合的伙伴,拓宽人脉,小栈会是你最好的选择。





点击进入>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP