Не делайте этого.
Почти невозможно создать потокобезопасный класс коллекции, в котором каждый метод получает блокировку.
Рассмотрим следующий экземпляр предложенного вами класса Concurrent.
Concurrent<vector<int>> vi;
Разработчик может прийти и сделать это:
int result = 0;
if (vi.size() > 0)
{
result = vi.at(0);
}
И другой поток может сделать это изменение между вызовами первых потоков size()
и at(0)
.
vi.clear();
Итак, теперь синхронизированный порядок операций:
vi.size() // returns 1
vi.clear() // sets the vector's size back to zero
vi.at(0) // throws exception since size is zero
Таким образом, даже если у вас есть потокобезопасный векторный класс, два конкурирующих потока могут привести к исключению, которое выдается в неожиданных местах.
Это просто самый простой пример.Существуют и другие способы, с помощью которых несколько потоков, пытающихся одновременно выполнять чтение / запись / итерацию, могут непреднамеренно нарушить вашу гарантию безопасности потока.
Вы упомянули, что весь этот мотив мотивирован громоздкостью этого шаблона:
vi_mutex.lock();
vi.push_back(1);
vi_mutex.unlock();
На самом деле, есть вспомогательные классы, которые сделают этот очиститель, а именно lock_guard, который будет использовать мьютекс для блокировки своего конструктора и разблокировки на деструкторе
{
lock_guard<mutex> lck(vi_mutex);
vi.push_back(1);
}
Затем другой код впрактика становится поточно-ориентированной ала:
{
lock_guard<mutex> lck(vi_mutex);
result = 0;
if (vi.size() > 0)
{
result = vi.at(0);
}
}
Обновление:
Я написал пример программы, используя ваш класс Concurrent для демонстрации состояния гонки, которое приводит к проблеме.Вот код:
Concurrent<list<int>> g_list;
void thread1()
{
while (true)
{
if (g_list->size() > 0)
{
int value = g_list->front();
cout << value << endl;
}
}
}
void thread2()
{
int i = 0;
while (true)
{
if (i % 2)
{
g_list->push_back(i);
}
else
{
g_list->clear();
}
i++;
}
}
int main()
{
std::thread t1(thread1);
std::thread t2(thread2);
t1.join(); // run forever
return 0;
}
В неоптимизированной сборке вышеприведенная программа вылетает за считанные секунды.(Розничная торговля немного сложнее, но ошибка все еще есть).