2015-01-05 2 views
2

У меня есть класс шаблона, подобный этому:Статический член со статическим мьютекса и потокобезопасности

template <typename T> 
class Foo { 
    public: 
     static void show() { 
      unique_lock<mutex> l {mtx}; 
      for (const auto& v : vec) { 
       cout << v << endl; 
      } 
     } 

     static void add (T s) { 
      unique_lock<mutex> l {mtx}; 
      vec.push_back (s); 
     } 

    private: 
     static mutex mtx; 
     static vector<T> vec; 
}; 

template <typename T> mutex Foo<T>::mtx; 
template <typename T> vector<T> Foo<T>::vec; 

и использование этого класса выглядит следующим образом:

Foo<string>::add ("d"); 
Foo<string>::add ("dr"); 
Foo<string>::add ("dre"); 
Foo<string>::add ("drew"); 
Foo<string>::show(); 

Не могли бы вы сказать мне, если этот класс является потокобезопасным? И если это не так, как сделать поточную безопасную версию?

Если я правильно понял, когда у нас есть класс с функциями-членами (не статическими) и мьютекс (не статическими), мы предотвращаем состояние гонки одного объекта, который прошел через потоки, правильно? И когда у нас есть что-то подобное этому, мы предотвращаем состояние гонки не для объекта, а для класса вместо этого - в данном случае для определенного типа, или я ошибаюсь?

ответ

0

Выглядит хорошо для меня. Вверх и до точки. mtx является «защитой» vec, чтобы гарантировать, что итерация в show() не может происходить во время изменения вектора во время add().

Рассмотрите возможность называть его vec_mtx, если это его роль.

Вверх и точка? Во-первых, ваше использование (фактически) не указывает на какую-либо резьбу, поэтому я не знаю (точно), чего вы пытаетесь достичь.

Например, если все эти добавления происходили в одном потоке и показывались в другом, ваш код (очевидно) не гарантирует, что у них есть все произошло до шоу. Он будет только гарантировать, что (логически) это происходит либо перед всеми из них, строго между двумя из них или после всех них.

Если вы не использовали ссылки на строковые объекты, которые вы передали или использовали тип T с конструктором «мелкой» копии, то у вас могут быть проблемы.

Рассмотрите Foo :: add (buffer); и продолжить модификацию буфера таким образом, чтобы show() выполнялся в одном потоке, тогда как strcat(buffer,.) выполняет на другом, а буфер временно не заканчивается '\ 0'. Boom! Закажите билет в Seg Fault City (где трава не зеленая, а девушки - довольно).

Вам нужно внимательно изучить (какие бывают проблемы), какие данные используются совместно и как. Почти все неквалифицированные операторы «X являются потокобезопасными» являются ложными для всех X. Вы всегда должны (всегда) квалифицировать, какое использование они безопасны и/или насколько их безопасность распространяется. Это идет 10 раз для шаблонов.

Практически все шаблонные «гарантии» могут быть снесены с помощью какого-либо массива С (или сложной структуры, содержащей указатель или ссылки в другом месте, передавая его в шаблон в виде нити здесь, пока вы его обманываете). внутренняя копия сама по себе будет небезопасной!

Существует повторяющаяся ошибка, что, если вы обмениваетесь данными с помощью какой-либо поточно-безопасной структуры обмена, такой как очередь, вы получаете какую-то гарантированную потокобезопасность, и вам никогда не нужно думать о это снова и может вернуться к вашему однопоточному мышлению.

Здесь заканчивается урок.

NB: В теории std::string может быть реализован на памяти голодали среды, которая агрессивно "Бассейны копию строки таким образом, что выставляет вас условиям гонки вы даже не представляли. Теория, которую вы понимаете.