免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 24884 | 回复: 40
打印 上一主题 下一主题

[学习] Linux系统编程之----如何开发无锁数据结构(获奖名单已公布-2013-7-12) [复制链接]

论坛徽章:
49
15-16赛季CBA联赛之福建
日期:2016-06-22 16:22:002015年亚洲杯之中国
日期:2015-01-23 16:25:12丑牛
日期:2015-01-20 09:39:23未羊
日期:2015-01-14 23:55:57巳蛇
日期:2015-01-06 18:21:36双鱼座
日期:2015-01-02 22:04:33午马
日期:2014-11-25 09:58:35辰龙
日期:2014-11-18 10:40:07寅虎
日期:2014-11-13 22:47:15申猴
日期:2014-10-22 15:29:50摩羯座
日期:2014-08-27 10:49:43辰龙
日期:2014-08-21 10:47:58
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-06-21 09:21 |只看该作者 |倒序浏览
获奖名单已公布,详情请看:http://bbs.chinaunix.net/thread-4090480-1-1.html

如何开发一个无锁数据结构,例如无锁队列,无锁缓存。

涉及到并行/并发计算时,通常都会想到加锁,加锁可以保护共享的数据,不过也会存在一些问题。
1. 由于临界区无法并发运行,进入临界区就需要等待,加锁使得效率的降低。多核CPU也不能发挥全部马力
2. 在复杂的情况下,很容易造成死锁,并发进程、线程之间无止境的互相等待。
3. 在中断/信号处理函数中不能加锁,给并发处理带来困难。
总之,在基于锁的多线程/多进程编程,你需要保证对竞争条件很敏感的共享数据上的任何操作,都通过加锁或解锁一个独占(mutex)来实现原子操作。

那么,在实际应用中,有没有优雅的无锁的数据结构实现呢,请大家各抒己见。

活动时间:2013年6月21日-7月10日

邀请嘉宾:
crazyhadoop,ChinaUnix论坛Linux环境编程版版主

本期奖品:
最佳经验分享奖5名,奖励《Linux高性能服务器编程》图书一本;
所有参与讨论的会员,即可获得社区积分20分

图书简介:

作者: 游双   
出版社:机械工业出版社
ISBN:9787111425199
上架时间:2013-5-30
出版日期:2013 年6月
开本:16开
页码:345
版次:1-1

样章阅读:

http://wenku.it168.com/d_001050115.shtml

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
21 [报告]
发表于 2013-06-23 13:18 |只看该作者

最近在看这块,说说我的理解,请大家指点。。。

1.先说说几个概念
锁只是同步方法的一种,同步分阻塞同步和非阻塞同步。
lockfree就可以保证非阻塞同步,同时也尽量保证了waitfree,但依然做不到完全的waitfree。

2.既然讨论无锁,就得说说有锁会导致的问题
a)死锁
多个锁不按顺序的话
b)优先级反转
可能高优先级的等待低优先级的
c)影响实时性
等锁时间不定
d)信号安全
信号处理中不能用锁
e)崩溃处理
崩溃时可能占着锁
f)抢占的影响
被抢占时可能还占着锁
g)影响整体性能
切换进程影响性能

最后,锁的实现是跟硬件相关的,自然影响移植性。

3.无锁首先得根据业务逻辑,这个是首要的。
脱离业务去有锁或无锁是没有意义的。
根据业务流程去简化,一般可以将锁的存在压缩到最小。另外锁只是同步机制的一种,应该还有其它选择。

4.如果已经将有锁的存在压缩到最小的数据结构了,就可以考虑无锁算法了。
通用的lock free算法都是针对基本的数据结构的:buffer,list,queue,map
基本原理就是CAS机制了。现在几乎所有的CPU指令都支持CAS的原子操作,X86下对应的是CMPXCHG汇编指令。(可见,lockfree是依赖于机器体系结构的,而且lockfree其实还是有锁的,只是CAS给压缩含义了)

一般CAS会封装成下面的形式:(以32bit机为例)
bool cas32( int * pVal, int oldVal, int newVal );
pVal 表示要比较和替换数值的地址,oldVal表示期望的值,newVal表示希望替换成的值。

gcc中:
http://gcc.gnu.org/onlinedocs/gcc-4.1.1/gcc/Atomic-Builtins.html
  1. bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
  2. type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
  3. These builtins perform an atomic compare and swap. That is, if the current value of *ptr is oldval, then write newval into *ptr.
  4. The “bool” version returns true if the comparison is successful and newval was written. The “val” version returns the contents of *ptr before the operation. 
复制代码
另外,gcc的对于内核中内存屏障也有封装:(内核的kfifo实现可以看到,内核在kfifo时有比CAS机制更加地lock free,用mb即可。当然mb实现也跟机器架构有关)
  1. __sync_synchronize (...)
  2. This builtin issues a full memory barrier.
复制代码
  1.     #define LOCK_PREFIX    "lock;"  
  2.     #define __sync_bool_compare_and_swap(mem, oldval, newval) \  
  3.       ({ __typeof (*mem) ret;                             \  
  4.              __asm __volatile (LOCK_PREFIX "cmpxchgl %2, %1;sete %%al; movzbl %%al,%%eax"                \  
  5.                                 : "=a" (ret), "=m" (*mem)                  \  
  6.                                 : "r" (newval), "m" (*mem), "a" (oldval)\  
  7.                                 :"memory");         \  
  8.                                   ret; })  
复制代码
returns true if the comparison is successful and newval was written.


5.下面以说说无锁队列的实现,说下我的理解
  1. EnQueue(x)   
  2. {
  3.     q = newrecord();
  4.     q->value = x;
  5.     q->next = NULL;

  6.     do{
  7.         p = tail;   
  8.     }while( CAS(p->next, NULL, q) != TRUE);  

  9.     CAS(tail, p, q);
  10. }
  11. DeQueue()        
  12. {
  13.     do{
  14.         p = head;
  15.         if(p->next == NULL){
  16.             returnERR_EMPTY_QUEUE;
  17.         }
  18.     while( CAS(head, p, p->next) != TRUE );
  19.     returnp->next->value;
  20. }
复制代码
由于是多线程编程,自然要考虑多些。
考虑加入队列的处理:如果thread 1 EnQueue(x)在成功完成第一个CAS,还没开始第二个CAS时挂掉了。那么other threads就会全死循环了:都在等着next字段为NUL的tail,但其实这个tail的next恒指向T1 在第一个CAS中新增的节点了。

解决此问题的修改后的:
  1. EnQueue(x)      
  2. {
  3.     q = newrecord();
  4.     q->value = x;
  5.     q->next = NULL;

  6.     p = tail;
  7.     oldp = p
  8.     do{
  9.         while(p->next != NULL)
  10.             p = p->next;
  11.     }while( CAS(p.next, NULL, q) != TRUE);  

  12.     CAS(tail, oldp, q);
  13. }
复制代码
这样既保证了即使T1 挂掉,但是T1新增的节点内存还能继续使用。



回复 1# send_linux

评分

参与人数 1可用积分 +2 收起 理由
crazyhadoop + 2 赞一个!

查看全部评分

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
2 [报告]
发表于 2013-06-21 10:37 |只看该作者
本帖最后由 hellioncu 于 2013-06-21 10:40 编辑

所谓的“无锁数据结构"其实不是真的没有锁,只是没有使用普通的那种锁,一般用原子操作(原子增、减、比较和交换CAS等)修改关键计数器、指针等,利用内存屏障避免乱序执行问题,在读写互斥时一般采用忙等待。

无锁数据结构的适用性比普通的有锁结构小,一般用于在读写冲突概率较小,而对性能又要求很高的场合。

至于死锁,解决的问题很简单,就是对资源的访问(加解锁)次序保持一致即可,跟是否使用“无锁数据结构“没有直接的关系。

论坛徽章:
1
天蝎座
日期:2013-12-06 18:23:58
3 [报告]
发表于 2013-06-21 11:45 |只看该作者
回复 2# hellioncu


    是的,无锁数据结构巧妙的规避了竞争条件。当然也是有代价的

论坛徽章:
1
狮子座
日期:2013-09-06 17:18:40
4 [报告]
发表于 2013-06-21 12:39 |只看该作者
这个要具体情况具体分析了吧 ,因为一些算法需要的就是一个流程下来的,不可能用什么方法把数据拆分处理这样就比较难办了。     另外涉及到多核的话是共享内存还是独立内存的体系结构也是有影响的。

    所以愚见   无锁数据结构,可以运算前把数据都拆分了 然后再运算....

论坛徽章:
18
卯兔
日期:2013-09-27 17:41:0615-16赛季CBA联赛之佛山
日期:2016-07-09 17:34:45操作系统版块每周发帖之星
日期:2015-12-02 15:01:04IT运维版块每日发帖之星
日期:2015-12-02 06:20:00IT运维版块每日发帖之星
日期:2015-10-07 06:20:00IT运维版块每日发帖之星
日期:2015-10-03 06:20:00IT运维版块每日发帖之星
日期:2015-10-01 06:20:00羊年新春福章
日期:2015-04-01 17:56:06拜羊年徽章
日期:2015-04-01 17:56:062015年迎新春徽章
日期:2015-03-04 09:49:452015年辞旧岁徽章
日期:2015-03-03 16:54:15天秤座
日期:2015-01-14 06:39:28
5 [报告]
发表于 2013-06-21 14:05 |只看该作者
本帖最后由 qingduo04 于 2013-06-21 14:08 编辑

     鱼和熊掌不能兼得啊!

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
6 [报告]
发表于 2013-06-21 15:46 |只看该作者
回复 1# send_linux
这个话题很有意义。顶一把


   

论坛徽章:
49
15-16赛季CBA联赛之福建
日期:2016-06-22 16:22:002015年亚洲杯之中国
日期:2015-01-23 16:25:12丑牛
日期:2015-01-20 09:39:23未羊
日期:2015-01-14 23:55:57巳蛇
日期:2015-01-06 18:21:36双鱼座
日期:2015-01-02 22:04:33午马
日期:2014-11-25 09:58:35辰龙
日期:2014-11-18 10:40:07寅虎
日期:2014-11-13 22:47:15申猴
日期:2014-10-22 15:29:50摩羯座
日期:2014-08-27 10:49:43辰龙
日期:2014-08-21 10:47:58
7 [报告]
发表于 2013-06-21 16:04 |只看该作者
Godbach 发表于 2013-06-21 15:46
回复 1# send_linux
这个话题很有意义。顶一把


分享分享嘛,呵呵

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
8 [报告]
发表于 2013-06-21 17:01 |只看该作者
高级,聆听高手教诲。

论坛徽章:
1
射手座
日期:2014-08-04 16:49:43
9 [报告]
发表于 2013-06-21 17:18 |只看该作者
这是一本好书,可惜只有TMD三章,  虽然有新东西 但是大部分都是TCP/IP卷的东东,  看来要看到高性能的部分 只能买书了

论坛徽章:
49
15-16赛季CBA联赛之福建
日期:2016-06-22 16:22:002015年亚洲杯之中国
日期:2015-01-23 16:25:12丑牛
日期:2015-01-20 09:39:23未羊
日期:2015-01-14 23:55:57巳蛇
日期:2015-01-06 18:21:36双鱼座
日期:2015-01-02 22:04:33午马
日期:2014-11-25 09:58:35辰龙
日期:2014-11-18 10:40:07寅虎
日期:2014-11-13 22:47:15申猴
日期:2014-10-22 15:29:50摩羯座
日期:2014-08-27 10:49:43辰龙
日期:2014-08-21 10:47:58
10 [报告]
发表于 2013-06-21 18:17 |只看该作者
hanzhenlll 发表于 2013-06-21 17:18
这是一本好书,可惜只有TMD三章,  虽然有新东西 但是大部分都是TCP/IP卷的东东,  看来要看到高性能的部分 ...


多多交流哈,可以有机会获赠的哦
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP