linux編程的108種奇淫巧計-9(Lock-free之二)

來源:互聯網
上載者:User

    接上回: linux編程的108種奇淫巧計-7(Lock-free實驗)    

  
本節增加test_and_set的原語和一個spinlock比較完整的實現(參照nginx spin lock),主要的變化在於插入了__asm__ ("pause")指令,且插入次數是嘗試鎖的次數的2次冪,有助於在減少重試次數,通過這一變化可以對比看出CPU100%佔用的問題得到了緩解。test_and_set指令在未來的部落格中還會繼續提到,cas,tas,fetch_and_add是這一系列中需要使用的僅有的3條原子操作。

  
test_and_set的語義為傳入一個地址將其無條件置1,並返回該地址值的原來值,如果原來是1,返回1,如果原來是非1,返回非1,這提供了一個關門的好處,如果變數是非1,在進入臨界區以後,該變數自動關門,後面的嘗試全部失敗因為是while(tas(V)==1)的操作,在使用完臨界區以後,將該值請零(reset),必然有一個會在spin的過程中拿到,但是這種調度是有偶然性的,因此可能會出現饑餓,而且並發數越多的情況下,越容易出現饑餓,spin的次數不易過大,本文指定為4096,該值可以根據實際環境調整,參見nginx源碼。

  

  
以下是實驗代碼:

/*************************************************************************

//編譯方法

//g++ test.cpp -o test_cas_imp -D CAS_IMP -lpthread
//g++ test.cpp -o test_cas_imp_all -D CAS_IMP_ALL -lpthread
//g++ test.cpp -o test_tas_imp -D TAS_IMP -lpthread
//g++ test.cpp -o test_tas_imp_all -D CAS_IMP_ALL -lpthread

/**************************************************************************

# include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <syscall.h>
#if defined(__x86_64__) 
        #define ATOMICOPS_WORD_SUFFIX "q" 
#else
        #define ATOMICOPS_WORD_SUFFIX "l"
#endif
static inline bool compare_and_swap(volatile size_t *p, size_t val_old, size_t val_new)
{
        char ret;
        __asm__ __volatile__("lock; cmpxchg" ATOMICOPS_WORD_SUFFIX " %3, %0; setz %1"
                        : "=m"(*p), "=q"(ret)
                        : "m"(*p), "r" (val_new), "a"(val_old)
                        : "memory");
        return (bool)ret;
}
static inline size_t fetch_and_add(volatile size_t *p, size_t add)
{
        unsigned int ret;
        __asm__ __volatile__("lock; xaddl %0, %1"
                        :"=r" (ret), "=m" (*p)
                        : "0" (add), "m" (*p)
                        : "memory");
        return ret;
};
static inline int test_and_set(volatile int *s)    /* tested */
{       int r;
        __asm__ __volatile__(
                        "xchgl %0, %1"
                        : "=r"(r), "=m"(*s)
                        : "0"(1), "m"(*s)
                        : "memory");

        return r;
}
static inline int reset(volatile int *s)
{
        *s = 0;
}

volatile size_t g_uCount;
pthread_mutex_t g_tLck=PTHREAD_MUTEX_INITIALIZER;
const size_t cnt_num = 10000000;
volatile int tas_lock = 0;

void* sum_with_cas_imp(void*)
{
        for(int i=0;i< cnt_num;++i) {
                for(;;) {
                        size_t u = g_uCount;
                        if(compare_and_swap(&g_uCount,u,u+1)){
                                break;
                        }
                }
        }
}
void* sum_with_tas_imp(void*)
{
        for(int i=0;i< cnt_num;++i) {
                while((test_and_set(&tas_lock))==1){}
                ++g_uCount;
                reset(&tas_lock);
        }
}

void* sum_with_cas_imp_all(void*)
{
        for(int i=0;i < cnt_num;) {
                for(;;)
                {
                        size_t u = g_uCount;
                        if(compare_and_swap(&g_uCount,u,u+1)){
                                goto L1;
                        }
                        for(size_t n=1;n<4096;n<<=1){
                                for(size_t i=0;i<n;i++){
                                        __asm__ ("pause") ;
                                }
                                u = g_uCount;
                                if(compare_and_swap(&g_uCount,u,u+1)){
                                        goto L1;
                                }

                        }
                        syscall(SYS_sched_yield);
                }
        L1:  ++i;
        }
}

// reference:http://nginx.sourcearchive.com/documentation/0.7.59-1/ngx__spinlock_8c-source.html

void* sum_with_tas_imp_all(void*)

{

        for(int i=0;i < cnt_num;++i) {

 

                for(size_t n = 1;(test_and_set(&tas_lock))==1;n<<=1){

                        if(n<4096){

                                for(size_t i=0;i<n;i++){

                                        __asm__ ("pause") ;

                                }

                        }

                        else{

                                syscall(SYS_sched_yield);

                                n = 1;

                        }

                }

                ++g_uCount;

                reset(&tas_lock);

        }

}       

void* sum(void*)

{
        #ifdef CAS_IMP
        sum_with_cas_imp(NULL);
        #endif

        #ifdef TAS_IMP
        sum_with_tas_imp(NULL);
        #endif

        #ifdef CAS_IMP_ALL
        sum_with_cas_imp_all(NULL);
        #endif

        #ifdef TAS_IMP_ALL
        sum_with_tas_imp_all(NULL);
        #endif
};

int main()
{
        pthread_t* thread = (pthread_t*) malloc(10*sizeof( pthread_t));
        for(int i=0;i<10;++i)
        {
                pthread_create(&thread[i],NULL,sum,NULL);
        }
        for(int i=0;i<10;++i)
        {
                pthread_join(thread[i],NULL);
        }
        printf("g_uCount:%d/n",g_uCount);
        free( thread );
}

 

我搜了一下也有一些不錯的文章供大家參考

(1)http://student.csdn.net/space.php?uid=45153&do=thread&id=7403

(2)http://www.ibm.com/developerworks/cn/linux/l-rwlock_writing/

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.