это нормально, чтобы получить доступ к значению (запись в поточно-безопасной карте), на которую указывает указатель внутри не поточно-безопасного контейнера? - PullRequest
0 голосов
/ 13 июня 2018

Например,

// I am using thread safe map from
// code.google.com/p/thread-safe-stl-containers
#include <thread_safe_map.h>

class B{
  vector<int> b1;
};

//Thread safe map
thread_safe::map<int, B> A;
B b_object;
A[1] = b_object;

// Non thread safe map.
map<int, B*> C;
C[1] = &A[1].second;

Значит, следующие операции по-прежнему безопасны для потоков?

Thread1:
for(int i=0; i<10000; i++) {
  cout << C[1]->b1[i];
}

Thread2:
for(int i=0; i<10000; i++) {
  C[1]->b1.push_back(i);
}

Есть ли проблемы в приведенном выше коде?Если так, как я могу это исправить?

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

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Нет, то, что вы там делаете, небезопасно.Способ реализации thread_safe_map состоит в том, чтобы захватить блокировку на время каждого вызова функции:

//Element Access
T & operator[]( const Key & x ) { boost::lock_guard<boost::mutex> lock( mutex ); return storage[x]; }

Блокировка снимается, как только завершается функция доступа, что означает, что любая модификация, которую вы делаете черезвозвращаемая ссылка не имеет защиты.

Этот метод не только полностью безопасен, но и очень медленный.

Здесь предлагается безопасный (эффективный), но очень экспериментальный способ блокировки контейнеров:https://github.com/isocpp/CppCoreGuidelines/issues/924 с исходным кодом здесь https://github.com/galik/GSL/blob/lockable-objects/include/gsl/gsl_lockable (беззастенчивый отказ от саморекламы).

0 голосов
/ 13 июня 2018

Как правило, контейнеры STL могут быть доступны из нескольких потоков, если все потоки либо:

  • чтение из одного контейнера

  • изменить элементы потокобезопасным способом

Вы не можете push_back (или erase, insert и т. д.) из одного потока и читать из другогонить.Предположим, что вы пытаетесь получить доступ к элементу в потоке 1, в то время как push_back в потоке 2 находится в середине перераспределения памяти вектора.Это может привести к сбою приложения, может вернуть мусор (или может сработать, если вам повезет).

Второй пункт относится к таким ситуациям:

std::vector<std::atomic_int> elements;

// Thread 1:
elements[10].store(5);

// Thread 2:
int v = elements[10].load();

В этом случаевы одновременно читаете и пишете атомарную переменную, но сам вектор не изменяется - только его элемент:

Редактировать: использование thread_safe::map ничего не меняет в вас 'повторный случай.В то время как изменение карты в порядке, изменение ее элементов - нет.Помещение std::vector в поточно-ориентированную коллекцию автоматически не делает ее также потоко-безопасной.

...