【智鹿空间】c++实现了一个简单的链表数据结构 MyList,其中包含基本的 Get 和 Modify 操作,

这段代码实现了一个简单的链表数据结构 MyList,其中包含基本的 GetModify 操作,并且支持多线程访问。此外,还使用了 EBR (Epoch-Based Reclamation) 技术来管理内存回收,以及 benchmark 库来进行性能测试。以下是对代码的逐行注释:

cpp 复制代码
#include <benchmark/benchmark.h>  // 引入 Google Benchmark 库
#include <mutex>                  // 引入 C++ 标准库中的互斥锁
#include "ebr.h"                  // 引入 EBR (Epoch-Based Reclamation) 相关头文件
#include "spin_lock.h"            // 引入自旋锁相关头文件

// 定义链表节点结构
struct Node {
  Node() : lock(), next(nullptr) {}  // 构造函数,初始化锁和下一个指针
  int key;                           // 键值
  int value;                         // 值
  Node *next;                        // 指向下一个节点的指针
  SpinLock lock;                     // 自旋锁,用于保护节点
};

// 定义节点释放类,用于自动删除节点
class NodeFree {
 public:
  NodeFree(Node *node) { delete node; }  // 构造函数,删除传入的节点
};

// 定义链表类
class MyList {
 public:
  MyList() {
    Node *pre_node = nullptr;
    auto *&cur_node = root_;  // 当前节点指针
    for (int i = 0; i < 10; i++) {
      cur_node = new Node;     // 创建新节点
      cur_node->key = i;       // 设置键值
      cur_node->value = i;     // 设置值
      cur_node->next = pre_node;  // 设置下一个指针
      pre_node = cur_node;     // 更新前一个节点指针
    }
  }

  // 获取节点值
  int Get(int key, int *value) {
    root_->lock.lock();  // 锁住根节点
    auto *cur_node = root_->next;  // 当前节点指针
    auto *pre_node = root_;  // 前一个节点指针
    while (cur_node != nullptr) {
      cur_node->lock.lock();  // 锁住当前节点
      pre_node->lock.unlock();  // 解锁前一个节点
      if (key == cur_node->key) {  // 如果找到键值
        *value = cur_node->value;  // 设置返回值
        cur_node->lock.unlock();  // 解锁当前节点
        return 0;  // 返回成功
      }
      pre_node = cur_node;  // 更新前一个节点指针
      cur_node = cur_node->next;  // 移动到下一个节点
    }
    pre_node->lock.unlock();  // 解锁最后一个节点
    return 1;  // 返回失败
  }

  // 修改节点值
  int Modify(int key, int value) {
    root_->lock.lock();  // 锁住根节点
    auto *cur_node = root_->next;  // 当前节点指针
    auto *pre_node = root_;  // 前一个节点指针
    while (cur_node != nullptr) {
      cur_node->lock.lock();  // 锁住当前节点
      pre_node->lock.unlock();  // 解锁前一个节点
      if (key == cur_node->key) {  // 如果找到键值
        cur_node->value = value;  // 修改值
        cur_node->lock.unlock();  // 解锁当前节点
        return 0;  // 返回成功
      }
      pre_node = cur_node;  // 更新前一个节点指针
      cur_node = cur_node->next;  // 移动到下一个节点
    }
    pre_node->lock.unlock();  // 解锁最后一个节点
    return 1;  // 返回失败
  }

  // 使用 EBR 的获取节点值
  int GetUseEbr(int key, int *value) {
    ebr_mgr_.StartRead();  // 开始读操作
    auto *cur_node = root_->next;  // 当前节点指针
    while (cur_node != nullptr) {
      if (key == cur_node->key) {  // 如果找到键值
        *value = cur_node->value;  // 设置返回值
        ebr_mgr_.EndRead();  // 结束读操作
        return 0;  // 返回成功
      }
      cur_node = cur_node->next;  // 移动到下一个节点
    }
    ebr_mgr_.EndRead();  // 结束读操作
    return 1;  // 返回失败
  }

  // 使用 EBR 的修改节点值
  int ModifyUseEbr(int key, int value) {
    root_->lock.lock();  // 锁住根节点
    auto *cur_node = root_->next;  // 当前节点指针
    auto *pre_node = root_;  // 前一个节点指针
    while (cur_node != nullptr) {
      cur_node->lock.lock();  // 锁住当前节点
      if (key == cur_node->key) {  // 如果找到键值
        auto *new_node = new Node;  // 创建新节点
        new_node->key = cur_node->key;  // 设置键值
        new_node->value = value;  // 设置值
        new_node->next = cur_node->next;  // 设置下一个指针
        pre_node->next = new_node;  // 更新前一个节点的下一个指针
        cur_node->lock.unlock();  // 解锁当前节点
        pre_node->lock.unlock();  // 解锁前一个节点
        ebr_mgr_.FreeObject(cur_node);  // 释放旧节点
        return 0;  // 返回成功
      }
      auto *next_node = cur_node->next;  // 获取下一个节点
      pre_node->lock.unlock();  // 解锁前一个节点
      pre_node = cur_node;  // 更新前一个节点指针
      cur_node = next_node;  // 移动到下一个节点
    }
    pre_node->lock.unlock();  // 解锁最后一个节点
    return 1;  // 返回失败
  }

 private:
  Node *root_;  // 根节点指针
  EbrManager<Node, NodeFree, 15> ebr_mgr_;  // EBR 管理器
};

// 定义基准测试类
class MyBenchmark : public benchmark::Fixture {
 public:
  void SetUp(const ::benchmark::State &state) override {}  // 设置基准测试

  MyList &GetMyList() { return l; }  // 获取 MyList 实例

 private:
  MyList l;  // MyList 实例
  std::once_flag flag;  // 一次性标志
};

constexpr int kKeySize = 10000;  // 定义键值大小

// 定义不使用 EBR 的多线程工作基准测试
BENCHMARK_DEFINE_F(MyBenchmark, MultiThreadedWorkNoUseEbr)(benchmark::State &state) {
  for (auto _ : state) {
    auto &mylist = GetMyList();  // 获取 MyList 实例
    if (0 == state.thread_index()) {  // 主线程
      // 修改操作
      for (int i = 0; i < kKeySize; i++) {
        mylist.Modify(i % 9, i);  // 修改节点值
      }
    } else {  // 其他线程
      // 获取操作
      for (int i = 0; i < kKeySize; i++) {
        int value;
        mylist.Get(i % 9, &value);  // 获取节点值
      }
    }
  }
}

// 定义使用 EBR 的多线程工作基准测试
BENCHMARK_DEFINE_F(MyBenchmark, MultiThreadedWorkUseEbr)(benchmark::State &state) {
  for (auto _ : state) {
    auto &mylist = GetMyList();  // 获取 MyList 实例
    if (0 == state.thread_index()) {  // 主线程
      // 修改操作
      for (int i = 0; i < kKeySize; i++) {
        mylist.ModifyUseEbr(i % 9, i);  // 修改节点值
      }
    } else {  // 其他线程
      // 获取操作
      for (int i = 0; i < kKeySize; i++) {
        int value;
        mylist.GetUseEbr(i % 9, &value);  // 获取节点值
      }
    }
  }
}

// 注册基准测试,并指定线程数
BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWorkNoUseEbr)->Threads(4);
BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWorkNoUseEbr)->Threads(8);
BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWorkNoUseEbr)->Threads(12);

BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWorkUseEbr)->Threads(4);
BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWorkUseEbr)->Threads(8);
BENCHMARK_REGISTER_F(MyBenchmark, MultiThreadedWorkUseEbr)->Threads(12);

BENCHMARK_MAIN();  // 运行基准测试

代码解释

  1. Node 结构体

    • 定义了一个链表节点,包含键值、值、下一个节点指针和自旋锁。
  2. NodeFree 类

    • 用于自动删除节点,构造函数中调用 delete 释放节点内存。
  3. MyList 类

    • 实现了一个简单的链表,支持 GetModify 操作。
    • GetModify 方法使用自旋锁来保护节点。
    • GetUseEbrModifyUseEbr 方法使用 EBR 技术来管理内存回收。
  4. MyBenchmark 类

    • 继承自 benchmark::Fixture,用于定义基准测试。
    • GetMyList 方法返回 MyList 实例。
  5. 基准测试定义

    • MultiThreadedWorkNoUseEbrMultiThreadedWorkUseEbr 分别定义了不使用 EBR 和使用 EBR 的多线程基准测试。
    • 主线程执行 Modify 操作,其他线程执行 Get 操作。
  6. 基准测试注册

    • 使用 BENCHMARK_REGISTER_F 注册基准测试,并指定不同线程数。
  7. 运行基准测试

    • BENCHMARK_MAIN 运行所有注册的基准测试。

通过这些注释,你应该能够更好地理解代码的结构和功能。如果有任何具体问题或需要进一步的帮助,请随时告知。

相关推荐
Chris _data1 分钟前
二叉树oj题解析
java·数据结构
我们的五年18 分钟前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
程序猿阿伟34 分钟前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链
Lenyiin1 小时前
02.06、回文链表
数据结构·leetcode·链表
爪哇学长1 小时前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
爱摸鱼的孔乙己1 小时前
【数据结构】链表(leetcode)
c语言·数据结构·c++·链表·csdn
烦躁的大鼻嘎2 小时前
模拟算法实例讲解:从理论到实践的编程之旅
数据结构·c++·算法·leetcode
IU宝2 小时前
C/C++内存管理
java·c语言·c++
fhvyxyci2 小时前
【C++之STL】摸清 string 的模拟实现(下)
开发语言·c++·string
C++忠实粉丝2 小时前
计算机网络socket编程(4)_TCP socket API 详解
网络·数据结构·c++·网络协议·tcp/ip·计算机网络·算法