免费注册 查看新帖 |

Chinaunix

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

[C] __sync_xxx 系列函数似乎我的理解有很大问题 [复制链接]

论坛徽章:
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
11 [报告]
发表于 2013-08-18 20:00 |只看该作者
回复 10# zhouzhenghui

测试代码你还要求那么多, 我已经成功了, 使用了一个全新的思路, 跟上面贴出来的完全不一样,
但无论实现复杂度还是性能来说应该都是成倍提升, 你的代码我没有自己读, 但整体感觉其实和我上面的思路差不多, 连出现的 bug 的表现都一样。

论坛徽章:
0
12 [报告]
发表于 2013-08-18 21:01 |只看该作者
代码乱的意思是贴出来的最好做些简化,至少调试需要的代码都去除掉,有助于别人阅读和借鉴。

方法的确不是唯一的,需要的话可以写出很多种,或者按个人的喜好,比如也可以如下写put和get,代码虽多了一些,但逻辑上一致了,也更容易理解:
  1.     static struct lognode* head = &root;
  2.     static struct lognode* tail = &root;
  3.     static struct lognode end;

  4.     void lognode_put(struct lognode* node)
  5.     {
  6.         struct lognode* last;
  7.         struct lognode* before;
  8.         do {
  9.             last = tail;
  10.             if (last == &end) {
  11.                 __sync_val_compare_and_swap(&tail, last, head);
  12.                 continue;
  13.             }
  14.             before = __sync_val_compare_and_swap(&(last->next), NULL, node);
  15.             if (before != NULL)
  16.                __sync_val_compare_and_swap(&tail, last, before);
  17.         } while (before != NULL);

  18.         __sync_val_compare_and_swap(&tail, last, node);
  19.     }

  20.     struct lognode* lognode_get()
  21.     {
  22.         struct lognode *node = head->next;
  23.         if (node == NULL) return &end;

  24.         __sync_val_compare_and_swap(&tail, head, node);
  25.         head->next = NULL;
  26.        
  27.         lognode_put(&end);

  28.         __sync_val_compare_and_swap(&tail, &end, head);

  29.         return node;
  30.     }
复制代码
通过增加了一个end节点作为分割消费者的原子化行为,代码仍然针对单个消费者。

论坛徽章:
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
13 [报告]
发表于 2013-08-18 22:04 |只看该作者
本帖最后由 zylthinking 于 2013-08-18 22:09 编辑
zhouzhenghui 发表于 2013-08-18 21:01
代码乱的意思是贴出来的最好做些简化,至少调试需要的代码都去除掉,有助于别人阅读和借鉴。

方法的确不 ...


你这个照样有 bug, 根本通不过我的测试代码

论坛徽章:
0
14 [报告]
发表于 2013-08-18 23:20 |只看该作者
呵呵,我学乖测试过了,至少在这种场景是没问题的。错误在哪里也说不出来,注意这次队列的末指针是比较cur != &end

论坛徽章:
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
15 [报告]
发表于 2013-08-18 23:37 |只看该作者
本帖最后由 zylthinking 于 2013-08-18 23:43 编辑
zhouzhenghui 发表于 2013-08-18 23:20
呵呵,我学乖测试过了,至少在这种场景是没问题的。错误在哪里也说不出来,注意这次队列的末指针是比较cur  ...


你自己试试嘛


  1. #define _GNU_SOURCE
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <stddef.h>
  5. #include <stdio.h>
  6. #include <assert.h>
  7. #include <pthread.h>

  8. #define  rmb()  __asm__ volatile("lfence":::"memory")
  9. #define  wmb()  __asm__ volatile("sfence":::"memory")

  10. struct lognode {
  11.     struct lognode* next;
  12. };


  13. static struct lognode root = {0};
  14.     static struct lognode* head = &root;
  15.     static struct lognode* tail = &root;
  16.     static struct lognode end;

  17. void lognode_put(struct lognode* node)
  18. {
  19.     struct lognode* last;
  20.     struct lognode* before ;
  21.     do {
  22.         last = tail;
  23.          before = __sync_val_compare_and_swap(&(last->next), NULL, node);
  24.         if (before != NULL)
  25.            __sync_val_compare_and_swap(&tail, last, before);
  26.     } while (before != NULL);

  27.     __sync_val_compare_and_swap(&tail, last, node);
  28. }

  29. #if 1
  30. struct lognode* lognode_get()
  31. {
  32.     if (head == tail) return head;

  33.     struct lognode *node = head->next;
  34.     if (!node) return head;

  35.     head->next = NULL;
  36.     lognode_put(head);

  37.     return node;
  38. }
  39. #else
  40. struct lognode* lognode_get()
  41. {
  42.     struct lognode *node = head->next;
  43.     if (node == NULL) return &end;

  44.     __sync_val_compare_and_swap(&tail, head, node);
  45.     head->next = NULL;

  46.     lognode_put(&end);

  47.     __sync_val_compare_and_swap(&tail, &end, head);

  48.     return node;
  49. }
  50. #endif

  51. #define nrp 10000
  52. #define nrt 1

  53. static volatile int run = 0;
  54. static struct lognode* pool = NULL;
  55. static volatile int indx = 0;

  56. void* writer(void* any)
  57. {
  58.     while (run == 0) {
  59.         usleep(100);
  60.     }

  61.     for (int i = 0; i < nrp; ++i) {
  62.         int idx = __sync_fetch_and_add(&indx, 1);
  63.         struct lognode* nodep = &pool[idx];
  64.         nodep->next = NULL;
  65.         lognode_put(nodep);
  66.     }

  67.     __sync_sub_and_fetch(&run, 1);
  68.     return NULL;
  69. }


  70. int main(int argc, char** argv)
  71. {
  72.     int n = 0;
  73.     for (int i = 0; i < nrt; ++i) {
  74.         pthread_t tid;
  75.         if(0 == pthread_create(&tid, NULL, writer, NULL)) {
  76.             ++n;
  77.             pthread_detach(tid);
  78.         }
  79.     }

  80.     int nr = nrp * n;
  81.     pool = (struct lognode *) malloc(sizeof(struct lognode) * nr);
  82.     if (pool == 0) {
  83.         printf("memory\n");
  84.         return 0;
  85.     }
  86.     run = n;
  87.     printf("run = %d\n", run);

  88.     printf("%d writer, nr = %d\n", n, nr);
  89.     time_t t1 = time(0);


  90.     while (run > 0) {
  91.         struct lognode* nodep = lognode_get();
  92.         struct lognode* cur = nodep;
  93.         while (cur != &end) {
  94.             nodep = nodep->next;
  95.             cur = nodep;
  96.             --nr;
  97.         }

  98.         time_t t2 = time(0);
  99.         if (t2 > t1 + 3) {
  100.             printf("%d %d\n", nr, indx);
  101.             t1 = t2;
  102.         }
  103.     }

  104.     struct lognode* nodep = lognode_get();
  105.     struct lognode* cur = nodep;
  106.     while (cur != &end) {
  107.         nodep = nodep->next;
  108.         cur = nodep;
  109.         --nr;
  110.     }

  111.     printf("done %d\n", nr);
  112.     return 0;
  113. }
复制代码
根据 #if 不同定义编译两次各自运行:
zylthinking@linux:~/code/test$ gcc a.c -lpthread -std=c99 -ggdb
zylthinking@linux:~/code/test$ ./a.out
run = 1
1 writer, nr = 10000
done 3981
zylthinking@linux:~/code/test$ gcc a.c -lpthread -std=c99 -ggdb
zylthinking@linux:~/code/test$ ./a.out
run = 1
1 writer, nr = 10000
Segmentation fault (core dumped)

论坛徽章:
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
16 [报告]
发表于 2013-08-18 23:38 |只看该作者
无论采用你最新的代码还是你之前说应该怎么做的代码, 我都有测试, 都通不过

论坛徽章:
0
17 [报告]
发表于 2013-08-18 23:48 |只看该作者
贴我的测试代码,简化了,避免不必要的复杂性
  1. #include <assert.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <pthread.h>

  6. struct lognode {
  7.     int value;
  8.     struct lognode* next;
  9. };

  10. #define nrp 10000
  11. #define nrt 50

  12.     static struct lognode root = {0};
  13.     static struct lognode* head = &root;
  14.     static struct lognode* tail = &root;
  15.     static struct lognode end;
  16.     static int sum = 0;
  17.     static volatile int run;

  18.     void lognode_put(struct lognode* node)
  19.     {
  20.         struct lognode* last;
  21.         struct lognode* before;
  22.         do {
  23.             last = tail;
  24.             if (last == &end) {
  25.                 __sync_val_compare_and_swap(&tail, last, head);
  26.                 continue;
  27.             }
  28.             before = __sync_val_compare_and_swap(&(last->next), NULL, node);
  29.             if (before != NULL)
  30.                __sync_val_compare_and_swap(&tail, last, before);
  31.         } while (before != NULL);

  32.         __sync_val_compare_and_swap(&tail, last, node);
  33.     }

  34.     struct lognode* lognode_get()
  35.     {
  36.         struct lognode *node = head->next;
  37.         if (node == NULL) return &end;

  38.         __sync_val_compare_and_swap(&tail, head, node);
  39.         head->next = NULL;
  40.        
  41.         lognode_put(&end);

  42.         __sync_val_compare_and_swap(&tail, &end, head);

  43.         return node;
  44.     }

  45. void* writer(void* any)
  46. {
  47.     while (run == 0) {
  48.         usleep(100);
  49.     }

  50.     for (int i = 0; i < nrp; ++i) {
  51.         struct lognode* nodep = malloc(sizeof(struct lognode));
  52.         int value = rand();
  53.         __sync_fetch_and_add(&sum, value);
  54.         nodep->value = value;
  55.         nodep->next = NULL;
  56.         lognode_put(nodep);
  57.     }

  58.     __sync_sub_and_fetch(&run, 1);
  59.     return NULL;
  60. }

  61. int main(int argc, char** argv)
  62. {

  63.     int n = 0;
  64.     for (int i = 0; i < nrt; ++i) {
  65.         pthread_t tid;
  66.         if(0 == pthread_create(&tid, NULL, writer, NULL)) {
  67.             ++n;
  68.             pthread_detach(tid);
  69.         }
  70.     }
  71.     run = n;

  72.     while (run > 0) {
  73.         struct lognode* nodep = lognode_get();
  74.         while (nodep != &end) {
  75.             __sync_sub_and_fetch(&sum, nodep->value);
  76.             nodep = nodep->next;
  77.         }
  78.     }

  79.     struct lognode* nodep = lognode_get();
  80.     while (nodep != &end) {
  81.         __sync_sub_and_fetch(&sum, nodep->value);
  82.         nodep = nodep->next;
  83.     }

  84.     assert(sum == 0);
  85.     printf("success\n");

  86. }

复制代码

论坛徽章:
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
18 [报告]
发表于 2013-08-18 23:52 |只看该作者
回复 17# zhouzhenghui

那应该是你走运了
我原样粘过去运行了一把:
zylthinking@linux:~/code/test$ gcc a.c -lpthread -std=c99 -ggdb
a.c: In function ‘writer’:
a.c:58:9: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]
zylthinking@linux:~/code/test$ ./a.out
Segmentation fault (core dumped)

论坛徽章:
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
19 [报告]
发表于 2013-08-18 23:53 |只看该作者

Program received signal SIGSEGV, Segmentation fault.
0x00000000004009b2 in main (argc=1, argv=0x7fffffffdf6 at a.c:90
90                    __sync_sub_and_fetch(&sum, nodep->value);
(gdb)

论坛徽章:
0
20 [报告]
发表于 2013-08-19 01:04 |只看该作者
本帖最后由 zhouzhenghui 于 2013-08-19 09:53 编辑

虽然我的测试显示没有问题,但我也承认get函数仍然存在不稳定逻辑,并且代码中稍微偷了一下懒,这样逻辑清晰一些。

因为我的测试都通过,我也没有看出导致问题的地方,希望看到更多负面测试结果。有问题也是有可能的,说明了设计并行程序的复杂性,同时只有在特殊情况下才可能复用静态数据。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP