注意指针修饰符的准确含义
生活随笔
收集整理的這篇文章主要介紹了
注意指针修饰符的准确含义
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
首先從一起多線程無鎖算法的事故說起,以下是一個無鎖棧的實現測試,但在開-O2以上優化的情況下它卻無法正常工作:
#include "lf_stack.h" #include "kn_list.h" #include "kn_time.h" #include "kn_thread.h" #include "kn_atomic.h"typedef struct lockfree_stack {volatile kn_list_node *head; }lockfree_stack,*lockfree_stack_t;static void lfstack_push(lockfree_stack_t ls,kn_list_node *n) {for( ; ;){ kn_list_node *lhead = ls->head;n->next = lhead;if(COMPARE_AND_SWAP(&ls->head,lhead,n))//if head unchange,set n to be the new headbreak;} }static kn_list_node* lfstack_pop(lockfree_stack_t ls) {for( ; ;){ kn_list_node *lhead = ls->head;if(!lhead) return NULL;kn_list_node *next = lhead->next; if(COMPARE_AND_SWAP(&ls->head,lhead,next)){lhead->next = NULL;return lhead;}} }volatile int count = 0; atomic_32_t c1 = 0; atomic_32_t c2 = 0;struct element{kn_list_node node;int value; };struct element *element_pool1; struct element *element_pool2;lockfree_stack lf_stack;void *producer1(void *arg) {printf("producer1\n");int i;while(1){for(i = 0; i < 10000000; ++i){struct element *ele = &element_pool1[i];ATOMIC_INCREASE(&c1);lfstack_push(&lf_stack,(kn_list_node*)ele);}while(c1 > 0){FENCE();kn_sleepms(0);}}printf("producer1 end\n");return NULL; }void *producer2(void *arg) {printf("producer2\n");int i;while(1){for(i = 0; i < 10000000; ++i){struct element *ele = &element_pool2[i];ATOMIC_INCREASE(&c2); lfstack_push(&lf_stack,(kn_list_node*)ele);}while(c2 > 0){FENCE();kn_sleepms(0);}}return NULL; }void *consumer(void *arg) {printf("consumer\n");volatile struct element *ele;uint32_t tick = 0;while(1){if((ele = (struct element*)lfstack_pop(&lf_stack))){if(count == 0){tick = kn_systemms();}if(++count == 5000000) {uint32_t now = kn_systemms();uint32_t elapse = (uint32_t)(now-tick);printf("pop %d/ms\n",count/elapse*1000);tick = now;count = 0; }if(ele->value == 1)ATOMIC_DECREASE(&c1);else if(ele->value == 2)ATOMIC_DECREASE(&c2);elseprintf("%d\n",ele->value); }}return NULL; }int main(){element_pool1 = calloc(10000000,sizeof(*element_pool1));element_pool2 = calloc(10000000,sizeof(*element_pool2));int i;for(i = 0; i < 10000000; ++i) element_pool1[i].value = 1;for(i = 0; i < 10000000; ++i) element_pool2[i].value = 2; lf_stack.head = NULL;kn_thread_t t1 = kn_create_thread(THREAD_JOINABLE);kn_thread_t t2 = kn_create_thread(THREAD_JOINABLE); kn_thread_t t3 = kn_create_thread(THREAD_JOINABLE); kn_thread_start_run(t1,producer1,NULL);kn_thread_start_run(t2,producer2,NULL); kn_thread_start_run(t3,consumer,NULL); getchar();return 0; }表現就是consumer執行一定次數的pop之后死活也無法再彈出元素.不知道各位看官看出問題在哪沒有.
當問題再次出現以后,我用調試器上去中斷,consumer線程,斷點正好在這行if(!lhead) return NULL;,lhead為NULL,我回到上一層棧查看實際上lockfree_stack.head字段并不是空,當我想查看lhead的地址時,顯示無法查看寄存器地址.
那么問題就明確了,編譯器把lhead存放在了寄存器,導致無法發現head實際已經被改變.那么問題來了,我明明將head標記為volatile的呀.
可是再仔細看看,volatile kn_list_node *head;修飾符在指針之前,意思是指向的是volatile變量,而我實際要的是,一個指針它本身是volatile的.ok,做相應的調整后kn_list_node * volatile head;,問題解決.
總之,對指針修飾符關鍵的一點就是,在*之前,修飾的是指向的目標.而在*之后才是修飾指針本身.
轉載于:https://www.cnblogs.com/sniperHW/p/4190088.html
總結
以上是生活随笔為你收集整理的注意指针修饰符的准确含义的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 添加CSS的四种方式
- 下一篇: Beta版本发布报告