免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
1234
最近访问板块 发新帖
楼主: koolcoy
打印 上一主题 下一主题

[算法] 什么情况下必须使用非递归锁? [复制链接]

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
31 [报告]
发表于 2012-10-31 14:56 |只看该作者
@zylthinking
your code is similar to the implement of spinlock.
but in logically, the "system call" spinlock is more effective than you implemented.
to notice that you lock the bus in a loop

  1. while(!__sync_bool_compare_and_swap(lkp, 0, 1)){...}
复制代码
as i know, linux kernel imp it in such as the following code
*NOTE* the following code is pusudo code

  1. spinlock{
  2. volatile long lock;
  3. valatile long wait;
  4. };

  5. volatile spinlock spin={0,1};

  6. void reqspinlock(volatile spinlock &){
  7.   long myid=interlock_add(&spinlock.lock);
  8.   while(myid+1!=spinlock.wait){}  // Wait for the lock owner to release spinlock
  9.   spinlock.wait++;  // release spinlock
  10. }
复制代码
the above code assume that interlock_add function return the previous value that before added.
and

  1. while(myid+1!=spinlock.wait){...}
复制代码
do not lock the bus at all.

论坛徽章:
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
32 [报告]
发表于 2012-10-31 15:53 |只看该作者
本帖最后由 zylthinking 于 2012-10-31 16:18 编辑
folklore 发表于 2012-10-31 14:56
@zylthinking
your code is similar to the implement of spinlock.
but in logically, the "system call ...


说的似乎 spin lock 不锁bus 似的;
不知道你是否真的理解了 spin lock, spin lock 是和我贴出的代码相似, 其实现类似于

    #define lock(lkp) do{  \
LABEL: \
        while(!__sync_bool_compare_and_swap(lkp, 0, 1)){    \
            goto LABEL;  \
        }   \
    }while(0)

什么叫自旋, 不放弃CPU 而是粗暴地直接 goto LABEL 这就叫自旋。
适用的情景只能在内核这种自己有权限禁止抢占的程序中, 他不担心自己被抢占, 也小心编码让自己尽量快的执行完; 这样同时在其他核上的程序就算陷入自旋, 也可以预计在极短的时间内可以获得该锁。
在用户模式下, 持有自旋锁的代码一旦被调度出去, 新激活的线程如果获取不了该锁, 只会无条件循环做无用功直到自己时间片耗尽
你倒是说说哪个性能高? 尤其是在单核下

不说别的, 就凭 spin lock 在主流库中不见踪影, 就足以反驳你所谓 spin lock 性能高了

论坛徽章:
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
33 [报告]
发表于 2012-10-31 16:02 |只看该作者
贴一个 2.4 内核的实现, 最新的似乎看起来更复杂了, 就不分析论了:

126static inline void spin_lock(spinlock_t *lock)
127{
128#if SPINLOCK_DEBUG
129        __label__ here;
130here:
131        if (lock->magic != SPINLOCK_MAGIC) {
132printk("eip: %p\n", &&here);
133                BUG();
134        }
135#endif
136        __asm__ __volatile__(
137                spin_lock_string
138                :"=m" (lock->lock) : : "memory");
139}


  55#define spin_lock_string \
  56        "\n1:\t" \
  57        "lock ; decb %0\n\t" \
  58        "js 2f\n" \
  59        LOCK_SECTION_START("") \
  60        "2:\t" \
  61        "cmpb $0,%0\n\t" \
  62        "rep;nop\n\t" \
  63        "jle 2b\n\t" \
  64        "jmp 1b\n" \
  65        LOCK_SECTION_END
  66

没锁总线?????

论坛徽章:
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
34 [报告]
发表于 2012-10-31 16:08 |只看该作者
本帖最后由 zylthinking 于 2012-10-31 16:11 编辑
folklore 发表于 2012-10-31 14:56
@zylthinking
while(myid+1!=spinlock.wait){...}.


在你看来就是没锁总线?
如果没看错, 这个wait 的作用在于实现先入先出语意, 用于实现更公平的竞争, 也就是所谓的排队自旋锁; 和锁总线没有半毛钱关系
你干嘛不看看你所谓的interlocked_add是怎么实现的???

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
35 [报告]
发表于 2012-10-31 18:54 |只看该作者
回复 33# zylthinking


    所有的锁都必然要锁总线,但你在一个循环中不断地锁。。。
  1. 在用户模式下, 持有自旋锁的代码一旦被调度出去, 新激活的线程如果获取不了该锁, 只会无条件循环做无用功直到自己时间片耗尽
  2. 你倒是说说哪个性能高?
复制代码
我说过用户态的Spinlock有性能上的风险(但也仅仅是风险)。
大多数Spin时间很短,几乎无竞争的情况下(我基本上会将系统设计成这样),这个风险是可以冒的。
如果你无限制地开一大群线程,竞争同一锁,自然是不行的。
  1. 不说别的, 就凭 spin lock 在主流库中不见踪影, 就足以反驳你所谓 spin lock 性能高了
复制代码
spinlock在主流库中不见踪影,是性能以外的原因更多,因为不是所有人都会遵守Spin的原则:最短时间内Release它。
此外,它的语义过于简单,对大多数人来说,“很难用”。

关于性能,你可能有更多的理由反驳我,但我只有一条依据:所有的锁都是基于Spinlock的,没有Spinlock,就无法实现基它任何锁。

当然,我也只能保证,自已能够认真的使用Spinlock,没敢说大家一起用吧。。。

论坛徽章:
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
36 [报告]
发表于 2012-10-31 19:13 |只看该作者
本帖最后由 zylthinking 于 2012-10-31 19:21 编辑
folklore 发表于 2012-10-31 18:54
回复 33# zylthinking
所有的锁都是基于Spinlock的,没有Spinlock,就无法实现基它任何锁


你是说所有的锁一旦申请不成功, 就回忙等吗?

至于说我不断锁, 这和主题本来就没多大关系, 何况就算不断锁了, 浪费的时间片是你那边哪个忙等的线程的时间片, 很显然, 我锁一下然后发现不行就让出时间片了, 比你什么事也不干, 就是不让出时间片来说, 还是比你性能高, 好歹我让出的时间片可以给其他线程用, 你的能拿来做什么? 就算是多核心, 锁总线影响其他核心, 也不过若干个总线周期, 一个线程空空浪费一个时间片是多少个周期, 能少于 10万个吗? 而且, 我的循环也不是忙等循环, 是 shedule_yield() 返回后的循环, 能循环几次???

更何况, 我本来也没维护不断锁导致的性能的问题, 只是说, 就算如此, 还是比 spin lock 性能高

论坛徽章:
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
37 [报告]
发表于 2012-10-31 19:15 |只看该作者
本帖最后由 zylthinking 于 2012-10-31 19:47 编辑
folklore 发表于 2012-10-31 18:54 回复 33# zylthinking 多数Spin时间很短,几乎无竞争的情况下(我基本上会将系统设计成这样),这个风险是可以冒的
其实你可以设计成绝对无竞争, 那么就什么锁也不用用了

一直强调你设计的竞争很少 那么同样竞争很少的情况下难道不是两者性能相当吗 有什么可说的 在频繁竞争下你的性能更低不是吗

最后 性能最高的其实从原理上来说其实是大路货pthread_mutex,至少linux上应该如此 没觉得讽刺?

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
38 [报告]
发表于 2012-10-31 19:47 |只看该作者
回复 37# zylthinking


    这个, MS还做不到。

基本无竞争,是指,基本上每次只有一个线程想拿到锁。
再者,因为锁很快被release,则在拿到锁期间被换出去的机率也将减小。
  1. 你是说所有的锁一旦申请不成功, 就回忙等吗?
复制代码
那就完了,因为其它锁就没意义了,再者,还有阻塞锁呢。

其它复杂语义的锁使用Spinlock来保护它的私有数据,比如等待队列。
做完了这个,它就马上要解放Spinlock锁。

至于说我不断锁, 这和主题本来就没多大关系, 何况就算不断锁了, 浪费的时间片是你那边哪个忙等的线程的时间片, 很显然, 我锁一下然后发现不行就让出时间片了, 比你什么事也不干, 就是不让出时间片来说, 还是比你性能高, 好歹我让出的时间片可以给其他线程用, 你的能拿来做什么? 就算是多核心, 锁总线影响其他核心, 也不过若干个总线周期, 一个线程空空浪费一个时间片是多少个周期, 能少于 10万个吗? 而且, 我的循环也不是忙等循环, 是 shedule_yield() 返回后的循环, 能循环几次???

对的,其实,while(myid+1!=spin.wait){}中间也是可以加shedule_yield() 的,就像Windows下可以用SwitchToThread一样,
只是MS shedule_yield不是Posix的,和本题无关,所有没加上。

论坛徽章:
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
39 [报告]
发表于 2012-10-31 19:50 来自手机 |只看该作者
加上了就不叫自旋锁了 不知有没有注意到

论坛徽章:
59
2015年亚洲杯之约旦
日期:2015-01-27 21:27:392015年亚洲杯之日本
日期:2015-02-06 22:09:41拜羊年徽章
日期:2015-03-03 16:15:432015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:50:282015元宵节徽章
日期:2015-03-06 15:50:392015年亚洲杯之阿联酋
日期:2015-03-19 17:39:302015年亚洲杯之中国
日期:2015-03-23 18:52:23巳蛇
日期:2014-12-14 22:44:03双子座
日期:2014-12-10 21:39:16处女座
日期:2014-12-02 08:03:17天蝎座
日期:2014-07-21 19:08:47
40 [报告]
发表于 2012-10-31 20:29 |只看该作者
回复 39# zylthinking


    对噬,加上了,就违反Spinlock的语义了。。。。
事实上只有内核态才会使用真正的自锁。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP