关山难越,谁悲失路之人;萍水相逢,尽是他乡之客。
百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程教程 > 技术文章 > 正文

C++核心准则CP.1: 设想你的代码?会成为多线程程序的一部分

guanshanw 2023-09-29 21:41 15 浏览 0 评论

CP.1: Assume that your code will run as part of a multi-threaded program

CP.1: 设想你的代码会成为多线程程序的一部分

Reason(原因)

It's hard to be certain that concurrency isn't used now or won't be used sometime in the future. Code gets reused. Libraries not using threads may be used from some other part of a program that does use threads. Note that this rule applies most urgently to library code and least urgently to stand-alone applications. However, over time, code fragments can turn up in unexpected places.

很难确定现在不需要并发或者将来的某个时间也不会使用。代码会被重用的。没有使用线程的库有可能被使用线程的、程序的其它部分使用。注意本准则对于功能库具有最大的紧迫性,而对于单独的应用程序就没什么紧迫性。然而,随着时间的推移,代码片段会出现在意想不到的地方。


Example, bad(反面示例)

double cached_computation(double x)
{
    // bad: these statics cause data races in multi-threaded usage
    static double cached_x = 0.0;
    static double cached_result = COMPUTATION_OF_ZERO;

    if (cached_x != x) {
        cached_x = x;
        cached_result = computation(x);
    }
    return cached_result;
}

Although cached_computation works perfectly in a single-threaded environment, in a multi-threaded environment the two static variables result in data races and thus undefined behavior.

虽然缓存计算可以在单线程环境中运行得很完美,但在多线程环境中,两个静态变量处于数据竞争状态,因此会导致无定义的行为。

Example, good(范例)

struct ComputationCache {
  double cached_x = 0.0;
  double cached_result = COMPUTATION_OF_ZERO;
  
  double compute(double x) {
    if (cached_x != x) {
      cached_x = x;
      cached_result = computation(x);
    }
    return cached_result;
  }
};

Here the cache is stored as member data of a ComputationCache object, rather than as shared static state. This refactoring essentially delegates the concern upward to the caller: a single-threaded program might still choose to have one global ComputationCache, while a multi-threaded program might have one ComputationCache instance per thread, or one per "context" for any definition of "context." The refactored function no longer attempts to manage the allocation of cached_x. In that sense, this is an application of the Single Responsibility Principle.

这段代码中,缓存数据存作为ComputationCache对象的数据成员存储,而不是静态的状态数据。这个重构从根本上将决定权向上委托给调用者:单线程程序可以继续使用全局的ComputationCache实例,而多线程程序可以每个线程管理一个ComputationCache实例,或者每个上下文一个实例,这个上下文可以有多种解释。重构的函数不再试图管理cached_x的内存分配。从这个角度来讲,这算是单独责任原则的一个应用。

In this specific example, refactoring for thread-safety also improved reusability in single-threaded programs. It's not hard to imagine that a single-threaded program might want two ComputationCache instances for use in different parts of the program, without having them overwrite each other's cached data.

在这个特定的例子中,目的在于线程安全的重构同时提高了单线程环境中的重用性。不难想象单线程有可能需要两个用于程序不同部分的ComputationCache实例,而不会发生缓存数据的相互覆盖。

There are several other ways one might add thread-safety to code written for a standard multi-threaded environment (that is, one where the only form of concurrency is std::thread):

存在很多其他的方式,其中一个是为了在标准的多线程环境(即,使用并发的唯一形式std::thread)中运行的代码中增加线程安全处理。

  • Mark the state variables as thread_local instead of static.
  • 将状态变量定义为线程内部的局部变量而不是静态变量。
  • Implement concurrency control, for example, protecting access to the two static variables with a static std::mutex.
  • 实现并发控制,例如,使用静态的std::mutex保护对两个静态变量的访问。
  • Refuse to build and/or run in a multi-threaded environment.
  • 拒绝在多任务环境中编译或执行代码。
  • Provide two implementations: one for single-threaded environments and another for multi-threaded environments.
  • 提供两种实现:一个用于单线程环境,另一个用于多线程环境。

Exception(例外)

Code that is never run in a multi-threaded environment.

永远不会运行于多线程环境的代码。

Be careful: there are many examples where code that was "known" to never run in a multi-threaded program was run as part of a multi-threaded program, often years later. Typically, such programs lead to a painful effort to remove data races. Therefore, code that is never intended to run in a multi-threaded environment should be clearly labeled as such and ideally come with compile or run-time enforcement mechanisms to catch those usage bugs early.

需要小心的是:存在很多事例本来被认为永远不会运行于多线程程序的代码最后成为多线程程序的一部分,通常是几年之后。一般来讲,为这样的程序消除数据竞争会非常痛苦。因此,一旦决定代码永远不会在多线程环境中运行,应该清晰地标记出来,而且最好同时提供编译和运行时的强制机制以尽早捕捉错误的用法。

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#cp1-assume-that-your-code-will-run-as-part-of-a-multi-threaded-program


觉得本文有帮助?请分享给更多人。

关注微信公众号【面向对象思考】轻松学习每一天!

面向对象开发,面向对象思考!

相关推荐

七条简单命令让您玩转Git
七条简单命令让您玩转Git

凭借着出色的协作能力、快速部署效果与代码构建辅助作用,Git已经得到越来越多企业用户的青睐。除了用于开发商业及消费级应用之外,众多科学及政府机构也开始尝试使用这...

2023-10-07 12:14 guanshanw

基本完整的关于Git分支branch的操作
基本完整的关于Git分支branch的操作

Git使用背景项目中要用到dev或者其他分支开发完代码,需要将该分支合并到master的需求操作步骤下面以dev名称为lex为分支名为例来操作一遍客户端操作:...

2023-10-07 12:14 guanshanw

Git 进阶(合并与变基)
Git 进阶(合并与变基)

在Git中整合来自不同分支的修改主要有两种方法:合并(merge)以及变基(rebase)合并(merge)merge流程图merge的原理是找到这两个分...

2023-10-07 12:13 guanshanw

Git学习笔记 003 Git进阶功能 part5 合并(第一部分)

合并(merge)是很常用的操作。尤其是一个庞大的很多人参与开发的企业级应用。一般会设定一个主分支,和多个副分支。在副分支开发完成后,合并到主分支中。始终保持主分支是一个完整的,稳定的最新状态的分支。...

非标题党,三张图帮你理解git merge和git rebase的区别
非标题党,三张图帮你理解git merge和git rebase的区别

初始场景:基于正常的开发分支修改几个小bug,然后在合并到开发分支上。gitmergegitcheckoutfeaturegitmergeho...

2023-10-07 12:13 guanshanw

git 初次使用(01)
git 初次使用(01)

先从github上克隆代码下来:使用vscode克隆代码如下图,填写上github仓库地址:vscode有时候克隆代码速度比较慢,可以用命令行方式克隆gitc...

2023-10-07 12:12 guanshanw

Git 远程操作

4.Git远程操作命令说明gitremote远程版本库操作gitfetch从远程获取版本库gitpull下载远程代码并合并gitpush上传远程代码并合并4.1远程版本库操作gitre...

Git常用命令-总结
Git常用命令-总结

创建git用户$gitconfig--globaluser.name"YourName"$gitconfig--globaluser.em...

2023-10-07 12:12 guanshanw

git中删除从别人clone下来项目的git信息,并修改为自己的分支

如果你从别人的Git存储库中克隆了一个项目,并想要删除与该存储库相关的Git信息,并将其修改为你自己的分支,则可以执行以下步骤:使用gitclone命令克隆存储库:gitclone<u...

git系列-回滚和放弃本地修改

回滚历史提交就是reset的功能。这种情况是已经提交远程仓库,需要回滚到之前的提交。gitreset--hardcommitId//注:强制提交后,当前版本后面的提交版本将会删掉!gi...

GIT使用小技巧大全
GIT使用小技巧大全

在大型软件工程的开发过程中,版本控制是无法绕过去的;目前来说,最火的版本控制软件就是GIT了。早两年SVN比较火,不过被大神linus喷了几次后,就日落西山了,...

2023-10-07 12:11 guanshanw

git相关命令-上
git相关命令-上

这些命令都是看了文档后,个人觉得比较有用的一些,展示给大家。回到远程仓库的状态抛弃本地所有的修改,回到远程仓库的状态。gitfetch--all&...

2023-10-07 12:10 guanshanw

Git命令行接口:掌握Git的必备技能
Git命令行接口:掌握Git的必备技能

Git是一款强大的分布式版本控制工具,它支持命令行界面操作。熟练掌握Git命令行接口,是开发者使用Git的必备技能之一。在这篇文章中,我们将介绍Git命令行接口...

2023-10-07 12:10 guanshanw

Git命令详解
Git命令详解

相信各位小伙伴们应该都对git有一些了解,毕竟作为代码管理的神器,就算不是IT行业的小伙伴肯定也或多或少的听说过一些。今天就来和小伙伴们分享一下自己总结的常用命...

2023-10-07 12:10 guanshanw

工作7年收集到的git命令
工作7年收集到的git命令

概念git中的术语解释:仓库也叫版本库(repository)stage:暂存区,add后会存到暂存区,commit后提交到版本库git安装linux...

2023-10-07 12:10 guanshanw

取消回复欢迎 发表评论: