免费注册 查看新帖 |

Chinaunix

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

关键字: 双向循环链表 + 生产/消费 + 多线程 + 锁 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-03-29 16:46 |只看该作者 |倒序浏览
本帖最后由 doofy 于 2010-03-29 18:25 编辑

现在纠结于一些基本的问题,有经验的过来帮忙澄清:

双向循环链表作为全局的数据结构,设置head_index和tail_index, 一个线程作为生产者,插入一个元素后,head_index自增,一个线程作为消费者,从队列中取出一个元素处理,tail_index自增;

问题:
这种模型下,能不能采取无锁设计?

欢迎拍砖~

补充:
我词不达意,我写了个demo,看下我的代码就应该明白我的意思了,不过这里确实是没什么好锁的, 两个线程只是读对方的index,改自己的index, 都是隔壁那个i++;++i ;i = i+1 害的!
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>

  7. #define MAX_LEN        10

  8. #define OFF                0x0
  9. #define ON                ~OFF

  10. #define unlikely(x)        __builtin_expect(!!(x), 0)

  11. struct node {
  12.         struct node *pre, *next;                       
  13.         u_int32_t state;
  14. };

  15. struct _block {
  16.         u_int32_t        insert_index;
  17.         u_int32_t        remove_index;
  18.         struct node list[MAX_LEN];
  19. } block;

  20. void init_list(struct node *list, int num)
  21. {
  22.         int i;
  23.         memset(list, 0, sizeof(*list) * num);

  24.         for(i = 1; i < MAX_LEN - 1; i++) {
  25.                 list[i].next = &list[i+1];
  26.                 list[i].pre        = &list[i-1];
  27.         }

  28.         list[0].next = &list[1];
  29.         list[0].pre = &list[MAX_LEN - 1];

  30.         list[MAX_LEN - 1].next = &list[0];
  31.         list[MAX_LEN - 1].pre = &list[MAX_LEN - 2];
  32. }


  33. void * producer_func(void *param)
  34. {
  35.         while(1) {
  36.                 if(block.insert_index == block.remove_index  \
  37.                         && block.list[block.insert_index].state == ON) {
  38.                         continue;               
  39.                 }
  40.                 block.list[block.insert_index].state = ON;
  41.                 if(unlikely(++block.insert_index == MAX_LEN))
  42.                         block.insert_index = 0;
  43.         }       
  44. }

  45. void * customer_func(void *param)
  46. {
  47.         while(1) {
  48.                 if(block.insert_index == block.remove_index  \
  49.                         && block.list[block.remove_index].state == OFF) {
  50.                         continue;               
  51.                 }
  52.                 block.list[block.remove_index].state = OFF;
  53.                 if(unlikely(++block.remove_index == MAX_LEN))
  54.                         block.remove_index = 0;
  55.         }
  56. }

  57. int main(void)
  58. {
  59.         pthread_t tid1, tid2;

  60.         block.insert_index = block.remove_index = 0;
  61.         init_list(block.list, MAX_LEN);

  62.         pthread_create(&tid1, NULL, customer_func, NULL);
  63.         pthread_create(&tid2, NULL, producer_func, NULL);

  64.         while(1)
  65.                 sleep(10);
  66.         return 0;
  67. }
复制代码

论坛徽章:
0
2 [报告]
发表于 2010-03-29 16:53 |只看该作者
无锁是不大可能的,但可以看上去无锁。
利用socket把一个链表做成一个服务器线程,接受-响应操作请求。这样一来,内核就替你解决同步问题了。

论坛徽章:
0
3 [报告]
发表于 2010-03-29 17:09 |只看该作者
觉得用一个大数组,而不用链表,不行么

论坛徽章:
0
4 [报告]
发表于 2010-03-29 17:18 |只看该作者
觉得用一个大数组,而不用链表,不行么
peidright 发表于 2010-03-29 17:09



  我本来的意思就是一个定长数组用来组织双向循环链表,整个过程中不会添加、删除节点!

论坛徽章:
0
5 [报告]
发表于 2010-03-29 17:31 |只看该作者
回复 4# doofy


    {:3_186:} ,那一般不这么叫。

这是可以实现无锁的吧。没有什么地方需要锁啊。只是如果一个线程太慢,或者一个线程太快,则整个系统阻塞?

搞多个这样的结构,多对这样的线程,会好些。

论坛徽章:
0
6 [报告]
发表于 2010-03-29 17:46 |只看该作者
锁保护的不是“链表”,它应当用来保护数据。。。
如果你要保护的数据,允许一定程度上多线程读写所产生的混乱,那么就不需要加锁了(最好不要用链表这种数据结构,用个数组吧)
反之,就摆脱不了锁。。。
仔细看看自己的设计,一定要明白为什么加锁

论坛徽章:
0
7 [报告]
发表于 2010-03-29 17:47 |只看该作者
其实游标不就相当于是锁了~?
我添了一个后备队列,用的std::queue;
生产者会先将queue的东西移动到数组;
若发现数组满了,就不移动了,消息放入queue;

消费者只操作数组,从数组取消息,解析;

感觉这样比较适用于强生产者和弱消费者场合

论坛徽章:
0
8 [报告]
发表于 2010-03-29 17:49 |只看该作者
利用socket把一个链表做成一个服务器线程,接受-响应操作请求。这样 ...
JohnBull 发表于 2010-03-29 16:53



    这个似乎跟LZ的问题没啥关系吧。。。

论坛徽章:
0
9 [报告]
发表于 2010-03-29 17:50 |只看该作者
队列可以无锁应该在特定的对象之间吧。
很多情况下做不到。
另外双向链表本身的指针用无锁维护,看似更加不可能。

当时实现这个多线程时
http://my.chinaunix.net/space-23480430-do-blog-id-2541.html
考虑蛮久锁定链表的问题。里面的thread, mutex, semaphore都用双向链表维护。
如果LZ有无锁的方案,欢迎探讨。

论坛徽章:
0
10 [报告]
发表于 2010-03-29 17:50 |只看该作者
其实游标不就相当于是锁了~?
我添了一个后备队列,用的std::queue;
生产者会先将queue的东西移动到数组 ...
okocha-jay 发表于 2010-03-29 17:47



    你还没明白应该保护啥。。。。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP