基于Lamport面包店算法实现的无等待互斥锁

13 篇文章 0 订阅

基于Lamport面包店算法实现的无等待互斥锁

本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

介绍

C语言实现的基于Lamport面包店算法的无等待互斥锁。可用于没有提供锁的系统,比如无RTOS的单片机中。

开源

API

// NWLCreate 创建锁
// total: 使用此锁的最大用户数量
// 返回锁的句柄.如果是0表示创建失败
intptr_t NWLCreate(int total);

// NWLDelete 删除锁
void NWLDelete(intptr_t handle);

// NWLLock 上锁.如果返回false表示上锁失败.上锁成功后必须要解锁
bool NWLLock(intptr_t handle, int id);

// NWLUnlock 解锁.必须上锁成功后才能解锁
void NWLUnlock(intptr_t handle, int id);

测试用例

windows下创建若干线程,按顺序打印数据。

#include <stdio.h>
#include <winsock2.h>
#include <process.h>
#include <windows.h>
#include <time.h>

#include "nowaitlock.h"

#pragma comment(lib,"ws2_32.lib")

#define MAX_THREAD_NUM 5

// 锁及保护的资源
static intptr_t lock;
// 顺序控制字
static int seq = 0;

static void case1(void);

static void case2(void);
static DWORD WINAPI thread(LPVOID lpParam);

int main() {
    case2();
    return 0;
}

static void case1(void) {
    intptr_t lock = NWLCreate(3);

    // 本轮应该0获取锁成功
    printf("---------->0\n");
    printf("0:%d\n", NWLLock(lock, 0));
    printf("1:%d\n", NWLLock(lock, 1));
    printf("2:%d\n", NWLLock(lock, 2));
    NWLUnlock(lock, 0);

    // 本轮应该0获取锁成功
    printf("---------->0\n");
    printf("0:%d\n", NWLLock(lock, 0));
    printf("1:%d\n", NWLLock(lock, 1));
    printf("2:%d\n", NWLLock(lock, 2));
    NWLUnlock(lock, 0);

    // 本轮应该1获取锁成功
    printf("---------->1\n");
    printf("1:%d\n", NWLLock(lock, 1));
    printf("0:%d\n", NWLLock(lock, 0));
    printf("2:%d\n", NWLLock(lock, 2));
    NWLUnlock(lock, 1);

    // 本轮应该2获取锁成功
    printf("---------->2\n");
    printf("2:%d\n", NWLLock(lock, 2));
    printf("0:%d\n", NWLLock(lock, 0));
    printf("1:%d\n", NWLLock(lock, 1));
    NWLUnlock(lock, 2);

    NWLDelete(lock);
}

static void case2(void) {
    lock = NWLCreate(MAX_THREAD_NUM);

    int a[MAX_THREAD_NUM] = {0};
    for (int i = 0; i < MAX_THREAD_NUM; i++) {
        a[i] = i;
        CreateThread(NULL, 0, thread, &a[i], 0, NULL);
    }
    while(1) {}
}

static DWORD WINAPI thread(LPVOID lpParam) {
    int id = *(int*)lpParam;

    printf("id:%d thread run\n", id);
    Sleep(1000);

    while (1) {
        if (NWLLock(lock, id) == false) {
            Sleep(0);
            continue;
        }

        printf("id:%d start\n", id);
        if (seq % MAX_THREAD_NUM == id) {
            seq++;
            printf("----->id:%d seq:%d\n", id, seq);
        }
        if (seq >= 20) {
            printf("id:%d exit\n", id);
            NWLUnlock(lock, id);
            break;
        }
        printf("id:%d stop\n", id);

        NWLUnlock(lock, id);
        Sleep(0);
    }
    return 0;
}

输出:

id:0 thread run
id:1 thread run
id:2 thread run
id:3 thread run
id:4 thread run
id:4 start
id:4 stop
id:0 start
----->id:0 seq:1
id:0 stop
id:2 start
id:2 stop
id:0 start
id:0 stop
id:1 start
----->id:1 seq:2
id:1 stop
id:2 start
----->id:2 seq:3
id:2 stop
id:1 start
id:1 stop
id:3 start
----->id:3 seq:4
id:3 stop
id:2 start
id:2 stop
id:4 start
----->id:4 seq:5
id:4 stop
id:0 start
----->id:0 seq:6
id:0 stop
id:1 start
----->id:1 seq:7
id:1 stop
id:2 start
----->id:2 seq:8
id:2 stop
id:0 start
id:0 stop
id:3 start
----->id:3 seq:9
id:3 stop
id:2 start
id:2 stop
id:3 start
id:3 stop
id:1 start
id:1 stop
id:4 start
----->id:4 seq:10
id:4 stop
id:0 start
----->id:0 seq:11
id:0 stop
id:1 start
----->id:1 seq:12
id:1 stop
id:2 start
----->id:2 seq:13
id:2 stop
id:1 start
id:1 stop
id:2 start
id:2 stop
id:1 start
id:1 stop
id:2 start
id:2 stop
id:4 start
id:4 stop
id:0 start
id:0 stop
id:4 start
id:4 stop
id:2 start
id:2 stop
id:3 start
----->id:3 seq:14
id:3 stop
id:4 start
----->id:4 seq:15
id:4 stop
id:2 start
id:2 stop
id:2 start
id:2 stop
id:4 start
id:4 stop
id:1 start
id:1 stop
id:1 start
id:1 stop
id:2 start
id:2 stop
id:3 start
id:3 stop
id:2 start
id:2 stop
id:3 start
id:3 stop
id:1 start
id:1 stop
id:3 start
id:3 stop
id:3 start
id:3 stop
id:3 start
id:3 stop
id:4 start
id:4 stop
id:1 start
id:1 stop
id:2 start
id:2 stop
id:2 start
id:2 stop
id:4 start
id:4 stop
id:0 start
----->id:0 seq:16
id:0 stop
id:2 start
id:2 stop
id:3 start
id:3 stop
id:0 start
id:0 stop
id:1 start
----->id:1 seq:17
id:1 stop
id:0 start
id:0 stop
id:3 start
id:3 stop
id:2 start
----->id:2 seq:18
id:2 stop
id:0 start
id:0 stop
id:3 start
----->id:3 seq:19
id:3 stop
id:4 start
----->id:4 seq:20
id:4 exit
id:2 start
id:2 exit
id:1 start
id:1 exit
id:0 start
----->id:0 seq:21
id:0 exit
id:3 start
id:3 exit

源码

最新源码请查看github或者gitee仓库。

nowaitlock.h

// Copyright 2021-2021 The jdh99 Authors. All rights reserved.
// 无等待锁.应用Lamport面包店算法
// Authors: jdh99 <jdh821@163.com>

#ifndef NOWAITLOCK_H
#define NOWAITLOCK_H

#include <stdint.h>
#include <stdbool.h>

// NWLCreate 创建锁
// total: 使用此锁的最大用户数量
// 返回锁的句柄.如果是0表示创建失败
intptr_t NWLCreate(int total);

// NWLDelete 删除锁
void NWLDelete(intptr_t handle);

// NWLLock 上锁.如果返回false表示上锁失败.上锁成功后必须要解锁
bool NWLLock(intptr_t handle, int id);

// NWLUnlock 解锁.必须上锁成功后才能解锁
void NWLUnlock(intptr_t handle, int id);

#endif

nowaitlock.c

// Copyright 2021-2021 The jdh99 Authors. All rights reserved.
// 无等待锁.应用Lamport面包店算法
// Authors: jdh99 <jdh821@163.com>

#include "nowaitlock.h"
#include <stdlib.h>
#include <string.h>

#pragma pack(1)

typedef struct {
    bool* entering;
    int* number;
    // 线程数量
    int total;
} tLock;

#pragma pack()

static int max(tLock* lock);

// NWLCreate 创建锁
// total: 使用此锁的最大用户数量
// 返回锁的句柄.如果是0表示创建失败
intptr_t NWLCreate(int total) {
    tLock* lock = (tLock*)malloc(sizeof(tLock));
    if (lock == NULL) {
        return 0;
    }
    memset(lock, 0, sizeof(tLock));

    lock->entering = malloc(sizeof(bool) * (uint64_t)total);
    if (lock->entering == NULL) {
        free(lock);
        return 0;
    }
    memset(lock->entering, 0, sizeof(bool) * (uint64_t)total);

    lock->number = malloc(sizeof(int) * (uint64_t)total);
    if (lock->number == NULL) {
        free(lock);
        return 0;
    }
    memset(lock->number, 0, sizeof(int) * (uint64_t)total);

    lock->total = total;
    return (intptr_t)lock;
}

// NWLDelete 删除锁
void NWLDelete(intptr_t handle) {
    if (handle == 0) {
        return;
    }
    tLock* lock = (tLock*)malloc(sizeof(tLock));
    free(lock->entering);
    free(lock->number);
    free(lock);
}

// NWLLock 上锁.如果返回false表示上锁失败.上锁成功后必须要解锁
bool NWLLock(intptr_t handle, int id) {
    tLock* lock = (tLock*)(handle);

    if (lock->number[id] == 0) {
        lock->entering[id] = true;
        lock->number[id] = 1 + max(lock);
        lock->entering[id] = false;
    }

    for (int j = 0; j < lock->total; j++) {
        if (lock->entering[j]) {
            lock->number[id] = 0;
            return false;
        }
        if (lock->number[j] != 0 &&
            (lock->number[j] < lock->number[id] || (lock->number[j] == lock->number[id] && j < id))) {
            lock->number[id] = 0;
            return false;
        }
    }
    return true;
}

static int max(tLock* lock) {
    int max = lock->number[0];
    for (int i = 1; i < lock->total; i++) {
        if (lock->number[i] > max) {
            max = lock->number[i];
        }
    }
    return max;
}

// NWLUnlock 解锁.必须上锁成功后才能解锁
void NWLUnlock(intptr_t handle, int id) {
    tLock* lock = (tLock*)(handle);
    lock->number[id] = 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值