前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++核心准则CP.2:避免数据竞争​

C++核心准则CP.2:避免数据竞争​

作者头像
面向对象思考
发布2020-07-02 15:33:27
4660
发布2020-07-02 15:33:27
举报

CP.2: Avoid data races

CP.2:避免数据竞争

Reason(原因)

Unless you do, nothing is guaranteed to work and subtle errors will persist.

除非你做到了,否则没有任何东西可以保证动作,微妙的错误还会继续存在。

Note(注意)

In a nutshell, if two threads can access the same object concurrently (without synchronization), and at least one is a writer (performing a non-const operation), you have a data race. For further information of how to use synchronization well to eliminate data races, please consult a good book about concurrency.

简而言之,如果两个线程可以(不进行任何同步)并发访问同一个对象,至少一个线程执行写操作(执行非常量操作),就会发生数据竞争。为了获得如何更好地使用同步以消除数据竞争的进一步信息,请查阅有关并发的经典书籍。

Example, bad(反面示例)

There are many examples of data races that exist, some of which are running in production software at this very moment. One very simple example:

有关数据竞争的例子非常多,有些就发生于正在运行的产品级软件。下面是很简单的例子:

代码语言:javascript
复制
int get_id()
{
  static int id = 1;
  return id++;
}

The increment here is an example of a data race. This can go wrong in many ways, including:

代码中的增量操作就是数据竞争的例子。出错的方式可以有很多种,包括:

  • Thread A loads the value of id, the OS context switches A out for some period, during which other threads create hundreds of IDs. Thread A is then allowed to run again, and id is written back to that location as A's read of id plus one.
  • 线程A获取id的值之后操作系统上下文从A中退出一段时间,这时另外的线程生成了几百个ID。接着线程A继续运行,这时id重新被写入,而值是A读取的局部变量加1之后的结果。
  • Thread A and B load id and increment it simultaneously. They both get the same ID.
  • 线程A和B同时获取id并加1。它们得到同样的ID。

Local static variables are a common source of data races.

局部静态变量是数据竞争的常见来源。

Example, bad(反面示例):

代码语言:javascript
复制
void f(fstream&  fs, regex pattern)
{
    array<double, max> buf;
    int sz = read_vec(fs, buf, max);            // read from fs into buf
    gsl::span<double> s {buf};
    // ...
    auto h1 = async([&] { sort(std::execution::par, s); });     // spawn a task to sort
    // ...
    auto h2 = async([&] { return find_all(buf, sz, pattern); });   // spawn a task to find matches
    // ...
}

Here, we have a (nasty) data race on the elements of buf (sort will both read and write). All data races are nasty. Here, we managed to get a data race on data on the stack. Not all data races are as easy to spot as this one.

这里,保存在buf中的元素会发生(严重的)数据竞争(排序既包含读操作也包含写操作)。没有哪个数据竞争是不严重的。代码中的数据竞争发生在堆栈中的数据。不是所有的数据竞争都像本例这样容易被发现。

Example, bad(反面示例):

代码语言:javascript
复制
// code not controlled by a lock

unsigned val;

if (val < 5) {
    // ... other thread can change val here ...
    switch (val) {
    case 0: // ...
    case 1: // ...
    case 2: // ...
    case 3: // ...
    case 4: // ...
    }
}

Now, a compiler that does not know that val can change will most likely implement that switch using a jump table with five entries. Then, a val outside the [0..4] range will cause a jump to an address that could be anywhere in the program, and execution would proceed there. Really, "all bets are off" if you get a data race. Actually, it can be worse still: by looking at the generated code you may be able to determine where the stray jump will go for a given value; this can be a security risk.

现在,编译器不知道val会被修改,因此编译结果很可能是一个带有五个分支的跳转表。那么一旦val的值超越了范围[0..4],就有可能调转到程序的任何位置并从那里继续执行。真的,一旦发生了数据竞争,结果会怎么样谁也不知道。实际上,还有可能更坏:通过检查生成的代码,你或许可以准确算出针对一个给定的值,程序可以跳转到什么位置。这可能成为一个安全风险。

Enforcement(实施建议)

Some is possible, do at least something. There are commercial and open-source tools that try to address this problem, but be aware that solutions have costs and blind spots. Static tools often have many false positives and run-time tools often have a significant cost. We hope for better tools. Using multiple tools can catch more problems than a single one.

有一些是可能的,至少做点什么。有些商用和开源工具试图定位这些问题,但是需要注意的是:解决方案需要成本并存在盲区。静态工具会产生很多误报,而运行时工具通常需要巨大的成本。我们希望出现更好的工具。使用多种工具会比单一工具捕捉更多的错误。

There are other ways you can mitigate the chance of data races:

存在另外的方法可以降低数据竞争的可能性:

  • Avoid global data
  • 避免全局数据
  • Avoid static variables
  • 避免静态数据
  • More use of value types on the stack (and don't pass pointers around too much)
  • 在堆栈上更多地使用值类型(并且不要来回传递指针)
  • More use of immutable data (literals, constexpr, and const)
  • 更多地使用不可修改的数据(literals, constexpr, and const)

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#cp2-avoid-data-races

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 面向对象思考 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CP.2: Avoid data races
  • Reason(原因)
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档