【智鹿空间】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 运行所有注册的基准测试。

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

相关推荐
胖咕噜的稞达鸭1 分钟前
AVL树手撕,超详细图文详解
c语言·开发语言·数据结构·c++·算法·visual studio
CSCN新手听安2 分钟前
【linux】多线程(六)生产者消费者模型,queue模拟阻塞队列的生产消费模型
linux·运维·服务器·c++
-SGlow-11 分钟前
Linux相关概念和易错知识点(48)(epoll的底层原理、epoll的工作模式、反应堆模式)
linux·服务器·c语言·网络·c++
csdn_aspnet29 分钟前
C++ 圆台体积和表面积计算程序(Program for Volume and Surface area of Frustum of Cone)
c++
阿林学习计算机1 小时前
红黑树的实现
数据结构
豐儀麟阁贵1 小时前
4.4数组的基本操作
java·开发语言·数据结构·算法
我狸才不是赔钱货1 小时前
AI大模型“战国策”:主流LLM平台简单介绍
c++·人工智能·程序人生·github·llama
无限进步_1 小时前
【C语言】在矩阵中高效查找数字的算法解析
c语言·开发语言·数据结构·c++·其他·算法·矩阵
Yupureki2 小时前
从零开始的C++学习生活 11:二叉搜索树全面解析
c语言·数据结构·c++·学习·visual studio
草莓工作室2 小时前
数据结构2:线性表1-线性表类型及其特点
c语言·数据结构