通过自动解锁从类返回锁定的资源

2023-11-24

我想要一个返回指向资源的指针的类成员函数。资源应自动锁定和解锁。我考虑创建一个不可复制的对象来处理锁定。

您认为以下是一个好的解决方案吗?它是线程安全的吗? STL 中是否已有适用于此用例的工具?

template<typename T, typename M>
struct LockedResource
{
private:
    T* data_;
    std::unique_lock<std::mutex> lock_;

public:
    LockedRessource(T* data, M& mtx) : data_{data}, lock_{mtx} {}
    T* data() const { return data_; }
};

用例示例:

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

class Foo {
private:
    std::vector<int> data_;
    std::mutex mtx_;
public:
    LockedResource<std::vector<int>,std::mutex> data()
    { return LockedResource<std::vector<int>,std::mutex>{&data_, mtx_}; }
};

Foo foo;

void worker(int worker, int iterations, int dt) {
    for(int i=0; i<iterations; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(dt));
        auto res = foo.data();
        // we now have a unique_lock until the end of the scope
        std::cout << "Worker " << worker << " adding " << i << std::endl;
        res.data()->push_back(i);
    }
}

int main() {
    std::thread t1{worker, 1, 10, 173};
    std::thread t2{worker, 2, 20, 87};    
    t1.join();
    t2.join();
}

这个想法 - 提供一个封装对同步对象的访问和必要的锁定的句柄 - 并不新鲜:请参阅通过同步值强制执行正确的互斥锁使用.

I liked Rook 的想法是使用unique_ptr带有手柄的自定义删除器,所以我想出了一个:

template <typename BasicLockable>
class unlock_deleter {
    std::unique_lock<BasicLockable> lock_;
public:
    unlock_deleter(BasicLockable& mtx) : lock_{mtx} {}
    unlock_deleter(BasicLockable& mtx, std::adopt_lock_t a) noexcept : lock_{mtx, a} {}

    template <typename T>
    void operator () (T*) const noexcept {
        // no-op
    }
};

template <typename T, typename M = std::mutex>
using locked_ptr = std::unique_ptr<T, unlock_deleter<M>>;

用于模板类的实现synchronized包装一个对象和一个互斥锁:

template <typename T, typename M = std::mutex>
class synchronized {
  T item_;
  mutable M mtx_;

  // Implement Copy/Move construction
  template <typename Other, typename N>
  synchronized(Other&& other, const std::lock_guard<N>&) :
    item_{std::forward<Other>(other).item_} {}

  // Implement Copy/Move assignment
  template <typename Other>
  void assign(Other&& other) {
    std::lock(mtx_, other.mtx_);
    std::lock_guard<M> _{mtx_, std::adopt_lock};
    std::lock_guard<decltype(other.mtx_)> _o{other.mtx_, std::adopt_lock};
    item_ = std::forward<Other>(other).item_;
  }

public:
  synchronized() = default;

  synchronized(const synchronized& other) :
    synchronized(other, std::lock_guard<M>(other.mtx_)) {}
  template <typename N>
  synchronized(const synchronized<T, N>& other) :
    synchronized(other, std::lock_guard<N>(other.mtx_)) {}

  synchronized(synchronized&& other) :
    synchronized(std::move(other), std::lock_guard<M>(other.mtx_)) {}    
  template <typename N>
  synchronized(synchronized<T, N>&& other) :
    synchronized(std::move(other), std::lock_guard<N>(other.mtx_)) {}    

  synchronized& operator = (const synchronized& other) & {
    if (&other != this) {
      assign(other);
    }
    return *this;
  }
  template <typename N>
  synchronized& operator = (const synchronized<T, N>& other) & {
    assign(other);
    return *this;
  }

  synchronized& operator = (synchronized&& other) & {
    if (&other != this) {
      assign(std::move(other));
    }
    return *this;
  }
  template <typename N>
  synchronized& operator = (synchronized<T, N>&& other) & {
    assign(std::move(other));
    return *this;
  }

  template <typename N>
  void swap(synchronized<T, N>& other) {
    if (static_cast<void*>(&other) != static_cast<void*>(this)) {
      std::lock(mtx_, other.mtx_);
      std::lock_guard<M> _{mtx_, std::adopt_lock};
      std::lock_guard<N> _o{other.mtx_, std::adopt_lock};

      using std::swap;
      swap(item_, other.item_);
    }
  }

  locked_ptr<T, M> data() & {
    return locked_ptr<T, M>{&item_, mtx_};
  }
  locked_ptr<const T, M> data() const& {
    return locked_ptr<const T, M>{&item_, mtx_};
  }
};

template <typename T, typename M, typename N>
void swap(synchronized<T, M>& a, synchronized<T, N>& b) {
  a.swap(b);
}

还要注意正确同步复制/移动/交换。这是您在 Coliru 现场运行的示例程序.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过自动解锁从类返回锁定的资源 的相关文章

  • 我的线程图像生成应用程序如何将其数据传输到 GUI?

    Mandelbrot 生成器的缓慢多精度实现 线程化 使用 POSIX 线程 Gtk 图形用户界面 我有点失落了 这是我第一次尝试编写线程程序 我实际上并没有尝试转换它的单线程版本 只是尝试实现基本框架 到目前为止它是如何工作的简要描述 M
  • 为什么大多数 C 开发人员使用 Define 而不是 const? [复制]

    这个问题在这里已经有答案了 在许多程序中 define与常量具有相同的用途 例如 define FIELD WIDTH 10 const int fieldWidth 10 我通常认为第一种形式优于另一种形式 它依赖于预处理器来处理基本上是
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • 构造函数中显式关键字的使用

    我试图了解 C 中显式关键字的用法 并查看了这个问题C 中的explicit关键字是什么意思 https stackoverflow com questions 121162 但是 那里列出的示例 实际上是前两个答案 对于用法并不是很清楚
  • 对齐 GridView 中的行值

    我需要在 asp net 3 5 中右对齐 gridview 列中的值 我怎样才能做到这一点
  • 如何使用recv()检测客户端是否仍然连接(并且没有挂起)?

    我写了一个多客户端服务器程序C on SuSE Linux 企业服务器 12 3 x86 64 我为每个客户端使用一个线程来接收数据 我的问题是 我使用一个终端来运行服务器 并使用其他几个终端来运行服务器telnet到我的服务器 作为客户端
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • 如何从 C# 控制器重定向到外部 url

    我使用 C 控制器作为网络服务 在其中我想将用户重定向到外部网址 我该怎么做 Tried System Web HttpContext Current Response Redirect 但没有成功 使用控制器的重定向 http msdn
  • IronPython:没有名为 json 的模块

    我安装了 IronPython 我的 python 文件如下所示 import sys print sys version import json 运行它的代码 var p Python CreateEngine var scope p C
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • C 语言中 =+(等于加)是什么意思?

    我碰到 与标准相反 今天在一些 C 代码中 我不太确定这里发生了什么 我在文档中也找不到它 In ancientC 版本 相当于 它的残余物与最早的恐龙骨头一起被发现 例如 B 引入了广义赋值运算符 使用x y to add y to x
  • 将数据打印到文件

    我已经超载了 lt lt 运算符 使其写入文件并写入控制台 我已经为同一个函数创建了 8 个线程 并且我想输出 hello hi 如果我在无限循环中运行这个线程例程 文件中的o p是 hello hi hello hi hello hi e
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 当“int”处于最大值并使用 postfix ++ 进行测试时,代码定义良好吗?

    示例 未定义行为的一个示例是整数溢出的行为 C11dr 3 4 3 3 int溢出是未定义的行为 但这是否适用于存在循环的以下内容 并且不使用现在超出范围的副作用i 特别是 这是否后缀增量规格帮助 结果的值计算在副作用之前排序 更新操作数的
  • System.Runtime.InteropServices.COMException(0x80040154):[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 C 项目中遇到异常 System Runtime InteropServices COMException 0x80040154 检
  • 有没有一种简单的方法可以让 Visual Studio 2015 使用特定的 ToolsVersion?

    使用特定版本构建项目或解决方案时msbuild我可以使用以下命令选择早期的 net 工具链 toolsversion or tv switch C Program Files x86 MSBuild 14 0 bin msbuild tv
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 什么是 __declspec 以及何时需要使用它?

    我见过这样的例子 declspec在我正在阅读的代码中 它是什么 我什么时候需要使用这个构造 这是 Microsoft 对 C 语言的特定扩展 它允许您使用存储类信息来赋予类型或函数属性 文档 declspec C https learn
  • WinRT 定时注销

    我正在开发一个 WinRT 应用程序 要求之一是应用程序应具有 定时注销 功能 这意味着在任何屏幕上 如果应用程序空闲了 10 分钟 应用程序应该注销并导航回主屏幕 显然 执行此操作的强力方法是在每个页面的每个网格上连接指针按下事件 并在触
  • 实例化 Microsoft.Office.Interop.Excel.Application 对象时出现错误:800700c1

    实例化 Microsoft Office Interop Excel Application 以从 winforms 应用程序生成 Excel 时 出现以下错误 这之前是有效的 但突然间它停止工作了 尽管代码和 Excel 版本没有变化 我

随机推荐

  • 如何在 Asp.Net MVC 中动态插入部分视图

    我正在将 Webforms 站点迁移到 MVC 在我的网络表单网站中 我的页面利用了用户控件的各种组合 然后是 html 块 然后是标签 文本框等 我不想对每个页面进行硬连线 因此我将从 CMS 驱动每个页面的输出 该 CMS 指定将控件插
  • bash Heredoc 可以将其结果直接放入变量中吗?

    我有一些这样的代码 CMD cat lt
  • 我的领域路径定义的 #if TARGET_OS_SIMULATOR 代码有什么问题?

    我有这个代码 if TARGET OS SIMULATOR let device false let RealmDB try Realm path Users Admin Desktop realm Realm realm else let
  • 检索 CSS 是否需要“getPropertyValue”方法?

    你能告诉我为什么我们需要使用getPropertyValue方法 如果我们只能使用getComputedStyle one 例如 据我了解 这将起作用 var s getComputedStyle element null opacity
  • 错误! “sudo”不是 Play 的有效属性

    我有一个 ansible 播放文件 它必须执行两个任务 第一个任务是在本地计算机上获取磁盘使用情况 另一个任务是获取远程计算机的磁盘使用情况并在远程计算机中安装 apache2 当我尝试运行该文件时出现错误 错误 sudo 不是 Play
  • 带有 json 正文的 Swagger POST

    我正在尝试使用 swagger 编写服务器响应的静态 json 文件 我被帖子正文困住了 不知道如何描述它 它看起来与 Grooveshark api 非常相似 其中有一个页面和不同的帖子参数 因此 给出grooveshark的例子 htt
  • 对 CollectionViewSource 感到困惑(SelectedItem 无法在组合中工作)

    我有一堆组合 它们都共享相同的可用选项 这些选择在我的 ViewModel 公开的集合中提供 一切都很好 花花公子 我现在想要对这些选择进行排序 所以我决定公开一个ICollectionView来自我的 ViewModel 而不是我平常的R
  • 将 plupload 与 MVC3 结合使用

    因此 我在 MVC3 中使用 flash 运行时实现了 plupload 它工作完美 因为它使用更正操作上传并运行全部内容 但是 我真的很希望能够控制响应 并在 plupload 中处理它 但我似乎无法得到任何响应 我尝试过覆盖 fileU
  • ambari hadoop 安装期间权限被拒绝(publickey、gssapi-keyex、gssapi-with-mic、密码)

    我正在尝试使用 ambari 部署 hadoop 集群 但是当我选择具有 FQDN 的主机名并继续配置时 我收到 ssh 的权限被拒绝错误 脚步 1 使用 ssh keygen 作为 root 生成 rsa 密钥 更改了 ssh 700 和
  • 我什么时候会使用 AppDomain?

    我对反射相当陌生 我想知道我会使用 第二个 AppDomain 做什么 在商业应用中会有什么实际应用 有很多用途 辅助 AppDomain 可以提供一定程度的隔离 类似于操作系统提供的进程隔离 我使用它的一个实际用途是动态加载 插件 DLL
  • 如何在android中将url加载到webview时显示进度?

    我正在将 url 加载到 webview 中 WebView webview WebView findViewById R id webview webview loadUrl url 加载网址需要一些时间 在此期间显示空白屏幕 我想在加载
  • 递归查询挑战 - 简单的父/子示例

    注意 在 postgresql 上的 RhodiumToad 的帮助下 我找到了一个解决方案 我将其作为答案发布 如果有人可以对此进行改进 请加入 我还没能适应之前的递归查询解决方案到以下有向无环图 其中包括多个 根 无祖先 节点 我正在尝
  • System.Diagnostics.Process.Start 针对不同域的进程

    我们有一个场景 我们需要用户能够启动 SQLServer 并使用与当前登录的域不同的域进行身份验证 因此 为了澄清其设置方式 用户到达办公室并登录公司域 为简单起见 我们将其称为 LOCALDOMAIN 他们希望连接到不同域上的远程数据库
  • TWTweetComposeViewController 中的错误?

    我正在使用 TWTweetComposeViewController 如果可用 从我的 iOS 应用程序内部发送推文 我用样板文本预先填充视图控制器 然后让用户自行修改和发送 它在大多数情况下都非常有效 蒸馏下来 它看起来像这样 与body
  • 测试|无法在resetFakeAsyncZone处读取未定义的属性“assertPresent”

    我的 karma v1 4 有问题 测试框架 我所有的单元测试现在都因错误而失败Cannot read property assertPresent of undefined at resetFakeAsyncZone 我已经搜索过解决方案
  • 让 eclipse 调试我的 android 项目

    我正在使用 Eclipse 编写 Android 应用程序 当我单击左侧树视图中的项目 然后单击 调试 时 IDE 会构建一个 APK 并按预期安装在模拟器 设备中 但是 如果我正在编辑文件并且忘记在尝试调试之前首先单击该项目 那么 IDE
  • 如何在网格视图的行命令中找到该控件?

    我怎么能够在 row 命令中找到控件网格视图 实际上 GridViewCommandEventArgs 中没有 Row 因此您需要从命令源命名容器中获取行 GridViewRow row GridViewRow Control e Comm
  • .NET 中的 Java 小程序相当于什么?

    NET 中的 Java 小程序相当于什么 是银光吗 Java applet 还在广泛使用吗 1997 年 当 Java 1 0 发布时 Java applet 是 新的热门事物 几年后 它们变得越来越不受欢迎 主要是因为在计算机上安装Jav
  • 如何实现像Gallery一样的Horizo​​ntalScrollView?

    I want to implement Horizontal ScrollView with some features of Gallery 在图库中 滚动条在一定距离处成对排列 即如果屏幕上显示三个图像 单击最后一个图像将排列在中心 我
  • 通过自动解锁从类返回锁定的资源

    我想要一个返回指向资源的指针的类成员函数 资源应自动锁定和解锁 我考虑创建一个不可复制的对象来处理锁定 您认为以下是一个好的解决方案吗 它是线程安全的吗 STL 中是否已有适用于此用例的工具 template