Поток безопасности и `const` - PullRequest
9 голосов
/ 12 декабря 2008

Как const (указатели, ссылки и функции-члены) помогают с безопасностью потоков в C ++?

Ответы [ 6 ]

14 голосов
/ 12 декабря 2008

Любые неизменяемые (то есть неизменяемые) данные по своей природе являются поточно-ориентированными - нет риска, что несколько потоков одновременно будут читать одни и те же данные только для чтения, потому что они никогда не изменятся!

Пометка переменной как const в C ++ делает ее доступной только для чтения и, таким образом, безопасной для потоков.

6 голосов
/ 12 декабря 2008

Функция-член const не должна изменять состояние, что делает безопасным вызов из нескольких потоков одновременно. Однако безопасность потока не является целью const, и C ++ предоставляет ключевое слово mutable и const_cast, означающее, что const фактически не гарантирует безопасность потока и на него нельзя полагаться для этой цели.

6 голосов
/ 12 декабря 2008

Основная проблема с несколькими потоками - изменчивость. const ограничивает это, но так как вы можете отбросить это, оно не является надежным.

4 голосов
/ 15 января 2009

C ++ const допускает использование неконстантных псевдонимов, таких как:

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

Учитывая это, const не дает никаких гарантий относительно неизменности ваших данных, даже если вы не выполняете кастинг или что-либо обходное. Если вы обращаетесь к myVar через ptr1, вы не можете изменить его через ptr1 (при условии, что я правильно понял синтаксис; это было намерением). Однако, он все еще может измениться через ptr2. То, что вы действительно хотите, это отдельная неизменная конструкция. Этого не существует в C ++.

4 голосов
/ 12 декабря 2008

Const функции не являются поточно-ориентированными. Обычно вы можете вызывать методы объекта 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 одновременно, это приведет к нарушению доступа. Вы должны использовать идиому блокировки чтения-записи. Несколько методов доступа могут быть вызваны одновременно, и только один модификатор может быть вызван одновременно. Exemple:

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 - это класс мьютекса из библиотеки потоков сборки потоков

3 голосов
/ 22 февраля 2012

Const и потокобезопасность - это ортогональные понятия.

Возьмем в качестве примера функцию const: класс может иметь как const, так и неконстантные функции, и один поток может вызывать неконстантную функцию, которая изменяет объект в то же время, когда другой поток находится в его const-функции. В этом случае маркировка функции const не обеспечивает никакой безопасности. Потоковая безопасность достигается только с помощью блокировки или других примитивов синхронизации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...