【问题标题】:C++11 Thread-safety with stack variables带有堆栈变量的 C++11 线程安全
【发布时间】:2012-01-03 04:55:39
【问题描述】:

我对 C++11 中的新线程有点困惑。我知道了如何使用互斥锁来阻止两个线程同时对同一数据进行操作,但是如何分配给该数据呢?

例子!

class Foo
{
    std::string s;

    // This would be called on a seperate thread
    void Bar() { s = std::string( "blah blah blah" ); }
};

所以我要问的是,因为我给 s 分配了一些东西,成员变量 s 是否总是停留在同一个内存位置,而分配只是改变内部数据,在这种情况下我只需要一个互斥体?或者我仍然可以遇到缓存值和意味着我需要开始使用 atomic 以确保我拥有最新数据的情况吗?还是仅适用于 int 或 structs 等类型?

【问题讨论】:

    标签: c++ multithreading thread-safety c++11 atomic


    【解决方案1】:

    互斥量保证足够。无论需要什么魔法来让它发挥作用,它们都包含。只要访问或修改s 的任何特定实例的每个线程都在 same 互斥锁的保护下这样做,就不会有问题。

    访问和赋值之间的唯一区别是——您不需要互斥锁来防止两个线程同时读取相同的数据。仅当一个对象可能在一个线程中被修改而另一个线程正在或可能正在访问它时,才需要互斥锁。允许并发读取。

    请注意,这是通常的规则,适用于std::string 等典型对象。如果愿意,可以创建一个对象,即使在并发读取时甚至在一个线程中读取一个对象而在另一个线程中读取相同类型的不同对象时也能中断。 (但这样的东西没有用,人们不应该制造它们。)

    【讨论】:

    • 称为“读取”的方法中写入只读对象时,这些对象不是会损坏吗?如果还有其他可能,我很乐意看到。
    • 没错。该操作在逻辑上是读操作,但包括物理写操作。 (例如,像GetValueOfParameter(std::string paramName) 这样的操作,如果参数不在内存中,则从 SQL 数据库中读取它。所有类型的写入都发生在那里。)或者考虑一个读取操作,在其遍历过程中查找您要求的信息会删除它找到的任何“过期”对象。
    • std::map::operator[],调用者很容易忘记它有时是写操作。我不会说“不应该制作它们”,而是“必须记录哪些操作需要外部同步,因为它们不是纯读取,即使它们看起来可能是”。
    • 编译器可能决定缓存 b,CPU 可能会,它可能会以多种方式出错。您可以使用原子类型或互斥体。两者都提供所需的语义。 (您不必找出可能出错的所有方法并修复它们,只需使用具有您需要的语义的构造即可。)
    • 理论上没关系。互斥锁实现做了任何需要的魔法来使它“正常工作”。在实践中,解释起来有点复杂。简短的版本是这样的:编译器不知道互斥锁/解锁函数的作用。所以它不能在对它们的调用中缓存 anything。 (就编译器所知,其他线程可以触及的任何东西,互斥锁/解锁函数都可以)。至于 CPU,它是通过缓存一致性逻辑在硬件中处理的。 (如果您想获得详细的答案,请提出一个具体的问题。这是一个非常简单的问题。)
    猜你喜欢
    • 2010-10-21
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多