2016-08-02 3 views
0

Я новичок в многопоточности, и я пытаюсь просто сделать некоторые std: lists thread-safe. Достаточно ли было бы делать mutex.lock() и mutex.unlock() всякий раз, когда элемент добавляется или удаляется в списки? Опять же, я только пытаюсь сделать их потокобезопасными.Threading-Safe std: list C++

Благодаря

ответ

2

Обратите внимание, что C++ не определяет поточно-, но определяет гонки данных, которая является состоянием, которое возникает, когда несколько потоков доступа к одному объекту и по крайней мере один из них является писателем.

Вы можете использовать мьютексы, чтобы выполнять функции члена от std::list<> данных гонки бесплатно. Вы можете даже сделать это для любого произвольного объекта с Wrapping C++ Member Function Calls technique by Bjarne Stroustrup. Это известно как внутренняя блокировка , что означает, что объект поддерживает свой собственный мьютекс.

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

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

+1

@Slava Очевидно, что функции-члены, которые указатели на утечки, ссылки и итераторы не могут быть потокобезопасными. Но вы даже не удосужились объяснить, почему, так что ваш комментарий близок к бесполезности. –

+0

ОП спрашивает, может ли он сделать поток 'std :: list <>' потокобезопасным, почти весь доступ к данным в списке требует итератора (за исключением тривиальных случаев, таких как передняя и задняя), поэтому нет, вы не можете сделать поток std :: list' safe просто блокировка мьютексов внутри списка методов. – Slava

+0

@Slava Это зависит от шаблона использования. Например, если 'std :: list <>' используется как очередь или стек, используются только 'push_back',' pop_front', 'pop_back'. –

1

Как правило, да. Если каждый поток/путь, который изменяет или читает список, блокирует один и тот же мьютекс, прежде чем делать это, доступ к списку можно считать потокобезопасным.

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

+0

Проблема в том, что OPs хотят сохранить сам мьютекс внутри списка и сделать его потокобезопасным. – Slava

+0

@ Слава, которая была/не поняла мне, как был сформулирован вопрос. –

4

Вы должны защитить весь доступ к списку, чтобы быть в безопасности. Хотя чтение из списка без блокировки не приведет к повреждению списка, если список изменен, когда другой поток читает его, либо поток может стать поврежденным (т. Е. Сбой или получить неверные результаты).

Вы должны держать блокировку для всего диапазона кода, который, как вы ожидаете, будет стабильным для содержимого. Это включает в себя любое время, когда у вас есть живые итераторы к его содержимому.

Использование std::lock_guard может помочь вам правильно управлять блокировкой. Просто создайте экземпляр его в начале любой области действия, которая будет обрабатывать ваш список, и в конце области действия она автоматически разблокируется, даже если область выходит за пределы исключения.

+0

Собственно, второй абзац неверен. Итераторы списков на самом деле стабильны. Однако я не вижу тривиального редактирования, чтобы сделать этот параграф правильным. Лучше всего переписать его. – MSalters

+0

@MSalters В каком смысле? Если другие потоки потенциально изменяют список, итераторы могут быть недействительными или те, к которым относятся эти итераторы, могут изменяться способами, которые приводят к поломке вашего кода. Может быть, * stable * - это не правильное слово, но я считаю, что утверждение в целом правильное. – nate

+0

@MSalters В моем первом абзаце только поток чтения стал коррумпированным, так как в примере не указано, что несколько незащищенных писателей, где они участвуют. Это происходит от OP, который заявил, что он собирается блокировать изменения, а не читать. – nate

0

Будет ли достаточно делать mutex.lock() и mutex.unlock() всякий раз, когда элемент добавляется или удаляется в списки?

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

Если возникает вопрос: «Можно ли помещать мьютекс внутри списка и сделать его потокобезопасным?» тогда ответ - нет, вы не можете.Если вы посмотрите на интерфейс std::list, вы увидите, что почти любой доступ к данным, который хранится в списке, выполняется с помощью итераторов, поэтому для создания std::list потокобезопасности потребуется сделать эти итераторы потоками безопасными, что не выполнимо (то есть, что вы будете делать, если итератор, который указывает удаленные данные устраняются).

 Смежные вопросы

  • Нет связанных вопросов^_^