线程安全和`const`

时间:2008-12-12 09:01:49

标签: c++ multithreading

const(指针,引用和成员函数)如何帮助C ++中的线程安全?

6 个答案:

答案 0 :(得分:14)

任何不可变(即不可变)的数据本质上都是线程安全的 - 多个线程同时读取相同的只读数据没有风险,因为它永远不会改变!

在C ++中将变量标记为const使其成为只读,从而使线程安全。

答案 1 :(得分:6)

多线程的主要问题是可变性。 const限制了这一点,但既然你可以抛弃常量,那就不是万无一失的。

答案 2 :(得分:6)

const成员函数不应该改变状态,这样可以安全地同时从多个线程调用。但是线程安全不是const的目的,C ++提供了mutable关键字和const_cast,这意味着const实际上并不保证线程安全,不应该依赖它。

答案 3 :(得分:4)

Const函数不是线程安全的。 Normaly,你可以同时从不同的线程调用const对象方法,但如果从不同的线程调用非const和const方法,你就会遇到竞争条件。检查一下:

class Foo
{
    size_t size_;
public:
    ...
    size_t get_size() const
    {
        return size_
    }
};

class Bar
{
    boost::shared_ptr<Foo> foo_;
public:
    //accessor
    size_t get_size() const
    {
        size_t size = 0;
        if (foo_)
            size = foo_->size();
        return size;
    }
    //modifiers
    void init()
    {
        foo_ = new Foo;
    }

    void clear()
    {
        foo_ = boost::shared_ptr<Foo>();
    }
};

如果有人调用init方法,然后同时调用clear和get_size方法,则会导致访问冲突。您必须使用读写锁定习语。可以同时调用多个访问器,并且只能同时调用一个修改器。 例:

class Bar
{
    boost::shared_ptr<Foo> foo_;
    mutable tbb::spin_rw_mutex lock_;
public:
    //accessor
    size_t get_size() const
    {
        size_t size = 0;
        //lock modifiers
        rw_mutex_type::scoped_lock lock(mutex, false);
        if (foo_)
            size = foo_->size();
        return size;
    }
    //modifiers
    void init()
    {
        //lock accessor and modifiers
        rw_mutex_type::scoped_lock lock(mutex, true);
        foo_ = new Foo;
    }

    void clear()
    {
        //lock accessor and modifiers
        rw_mutex_type::scoped_lock lock(mutex, true);
        foo_ = boost::shared_ptr<Foo>();
    }
};

tbb :: spin_rw_lock是来自threading builing blocks library

的互斥类

答案 4 :(得分:4)

C ++ const允许非常量别名,例如:

Foo myVar;
const Foo* ptr1;
Foo* ptr2;

鉴于此,const不保证数据的不变性,即使您没有进行任何转换或任何事情来绕过它。如果您通过ptr1访问myVar,则无法通过ptr1更改它(假设我的语法正确;这就是意图。)但是,它仍然可以通过ptr2进行更改。你真正想要的是一个单独的不可变构造。这在C ++中不存在。

答案 5 :(得分:3)

Const和线程安全是正交概念。

以const函数为例:一个类可能同时具有const和非const函数,并且一个线程可能正在调用一个非const函数,该函数在另一个线程处于其const函数的同时修改该对象。在这种情况下,标记功能const不会提供任何安全性。只有使用锁定或其他同步原语才能实现线程安全。