程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 自旋鎖

自旋鎖

編輯:關於C

下面的代碼實現了一個簡陋的自旋鎖。
由於僅僅是用於實驗的原型代碼,
所以可能包含許多錯誤和不適當的地方。
如果在信號處理函數中使用該鎖,
可能會死鎖。
該代碼用於Linux環境,在fedora11中測試過。


spin_lock.h:
=========================================================================
// 2011年 09月 13日 星期二 10:43:03 CST
// author: 李小丹(Li Shao Dan) 字 殊恆(shuheng)
// K.I.S.S
// S.P.O.T

#ifndef MEM_LOCK_H
#define MEM_LOCK_H

#include <unistd.h>
#include <sched.h>
#include <sys/syscall.h>

 

#if ((defined(__GNUC__) && \
    ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)))))
//#if 0

#pragma message "builtin on intel"

#define atomic_test_and_set(a)  __sync_lock_test_and_set(a, 1)
#define atomic_clear(a)         __sync_lock_release(a);

#elif (defined(__i386__) || defined(__x86_64__))

#pragma message "not builtin on intel"


inline static unsigned long
        atomic_test_and_set(volatile unsigned long *a)
{
    const unsigned long n = 1, old = 0;
    unsigned long ret;
    __asm__ __volatile__ (
            " lock; "
            " cmpxchgl %3, %1; "
            : "=a" (ret)
            : "m" (*a), "a" (old), "r" (n)
            : "memory", "cc"
            );
    return ret;
}

inline static void atomic_clear(volatile unsigned long *a)
{
    assert(*a);
    unsigned long ret, n = 0;
    __asm__ __volatile__ (
            " lock; "
            "xchgl %0, %1"
            : "=r" (ret)
            : "m" (*a), "0" (n)
            : "memory"
            );
}

#endif

 

typedef struct {
    volatile unsigned long tid;
    volatile unsigned long lock;
    volatile unsigned long recur;
} spin_lock_t;

inline static void spin_lock_init(spin_lock_t *);
inline static int spin_lock_lock(spin_lock_t *);
inline static int spin_lock_unlock(spin_lock_t *);

inline static void spin_lock_init(spin_lock_t *lk)
{
    lk->tid = 0;
    lk->lock = 0;
    lk->recur = 0;
}

#define SPIN_YIELD_INTERVAL 63U

inline static int spin_lock_lock(spin_lock_t *lk)
{
    pid_t now = syscall(SYS_gettid);
    int c = 0;
    for(;;) {
        if(!atomic_test_and_set(&lk->lock)) {
            // XXX: at the moment,
            // receive a signal and signal handler use the spin lock,
            // dead lock;
            lk->tid = (unsigned long)now;
            lk->recur = 1;
            return 0;
        }
        if(lk->tid == (unsigned long)now)
            return ++lk->recur;

        if(!(++c & SPIN_YIELD_INTERVAL))
            sched_yield();
    }
    return 0;
}

inline static int spin_lock_unlock(spin_lock_t *lk)
{
    unsigned long now =
        (unsigned long)syscall(SYS_gettid);

    if(lk->tid != now)
        return -1;

    if(!--lk->recur) {
        lk->tid = 0;
        atomic_clear(&lk->lock);
    }
    return 0;
}

#endif


摘自 leeshuheng的專欄
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved