Linux下用户态自旋锁的实现

#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>


#define SPIN_LOCK       1

static uint32_t atomic_cmp_set(uint32_t *lock, uint32_t old, uint32_t set)
{
    uint8_t rslt = 0;

    asm volatile ("lock;" // lock if SMP
                  "cmpxchgl %3, %1;"
                  "sete %0;"
                  : "=a" (rslt)
                  : "m" (*lock), "a" (old), "r" (set)
                  : "cc", "memory");

    return rslt;
}

static uint32_t g_continue = 1;
static volatile uint32_t g_count1 = 0;
static volatile uint32_t g_count2 = 0;
static uint32_t g_lock = 0;

static void *thread_func(void *p_param)
{
    while (g_continue) {
    #if SPIN_LOCK
        while (!atomic_cmp_set(&g_lock, 0, 1)) {
            sched_yield();
        }
    #endif
 
        ++g_count1;
        ++g_count2;
 
    #if SPIN_LOCK
        g_lock = 0;
    #endif
    }

    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t t1 = 0, t2 = 0;

    pthread_create(&t1, NULL, &thread_func, NULL);
    pthread_create(&t2, NULL, &thread_func, NULL);
    sleep(1);
    g_continue = 0;
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    fprintf(stderr,
            "%u, %u\n",
            g_count1,
            g_count2);

    return 0;
}

##########################################################################################
##########################################################################################
增加进程同步
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/wait.h>


#define THREAD          0
#define SPIN_LOCK       1

#if SPIN_LOCK
static uint32_t atomic_cmp_set(uint32_t *lock, uint32_t old, uint32_t set)
{
    uint8_t rslt = 0;

    assert(NULL != lock);
    asm volatile ("lock;" // lock if SMP
                  "cmpxchgl %3, %1;"
                  "sete %0;"
                  : "=a" (rslt)
                  : "m" (*lock), "a" (old), "r" (set)
                  : "cc", "memory");

    return rslt;
}
#endif

#if THREAD
static uint32_t g_continue = 1;
#else
static void *gp_continue = NULL;
#endif
#if THREAD
static volatile uint32_t g_count1 = 0;
static volatile uint32_t g_count2 = 0;
#else
static volatile void *gp_count1 = 0;
static volatile void *gp_count2 = 0;
#endif

static int shmid = 0;
#if SPIN_LOCK
#if THREAD
static uint32_t g_lock = 0;
#else
static void *gp_lock = NULL;
#endif
#endif

static void *thread_func(void *p_param)
{
#if THREAD
    while (g_continue) {
#else
    while (*(uint32_t *)gp_continue) {
#endif
    #if SPIN_LOCK
    #if THREAD
        while (!atomic_cmp_set(&g_lock, 0, 1)) {
    #else
        while (!atomic_cmp_set((uint32_t *)gp_lock, 0, 1)) {
    #endif
            sched_yield();
        }
    #endif

    #if THREAD
        ++g_count1;
        ++g_count2;
    #else
        ++(*(volatile uint32_t *)gp_count1);
        ++(*(volatile uint32_t *)gp_count2);
    #endif

    #if SPIN_LOCK
    #if THREAD
        g_lock = 0;
    #else
        *(uint32_t *)gp_lock = 0;
    #endif /* THEAD */
    #endif
    }

#if SPIN_LOCK
#if !THREAD
    shmdt(gp_lock);
#endif
#endif

    return NULL;
}

int main(int argc, char *argv[])
{
    // 创建共享内存
    shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0600);
    if (-1 == shmid) {
        return -1;
    }

#if THREAD
    pthread_t t1 = 0, t2 = 0;

    pthread_create(&t1, NULL, &thread_func, NULL);
    pthread_create(&t2, NULL, &thread_func, NULL);
    sleep(1);
    g_continue = 0;
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

#else
#if SPIN_LOCK
    gp_lock = shmat(shmid, 0, 0);
    *(uint32_t *)gp_lock = 0;
#endif
    gp_continue = ((char *)shmat(shmid, 0, 0)) + 4;
    *(uint32_t *)gp_continue = 1;
    gp_count1 = ((char *)shmat(shmid, 0, 0)) + 8;
    *(uint32_t *)gp_count1 = 0;
    gp_count2 = ((char *)shmat(shmid, 0, 0)) + 12;
    *(uint32_t *)gp_count2 = 0;

    switch (fork()) {
    case 0:
        break;
    case -1:
        exit(-1);
    default:
        {
            int x = fork();

            if (x > 0) {
                sleep(1);
                *(uint32_t *)gp_continue = 0;
                wait(NULL);
                shmdt(gp_continue);
                (void)shmctl(shmid, IPC_RMID, 0);
                exit(0);
            }
        }
    }

    thread_func(NULL);

#endif

    fprintf(stderr,
            "%u, %u\n",
        #if THREAD
            g_count1,
            g_count2);
        #else
            *(volatile uint32_t *)gp_count1,
            *(volatile uint32_t *)gp_count2);
        #endif

    return 0;
}




ps: 汇编代码源自nginx,CAS机制只能实现自旋锁,因为用户态无法挂起唤醒线程,可以借助futex实现互斥锁。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值