следует ли мне использовать блокировку, если я уверен, что каждый поток всегда будет записывать одно и то же значение в общую память? - PullRequest
3 голосов
/ 02 августа 2020

C ++: у меня vector<bool>, ни один поток никогда не напишет false ни в один из индексов. Стоит ли мне по-прежнему использовать блокировку? Я не думаю, что это вызовет состояние гонки, поскольку все потоки пишут одно и то же значение. Функции, к которым обращаются несколько потоков, выглядят так:

void setVal(int index) 
{
  if (boolvec[index] == false)
    boolvec[index] = true; 
}

Ответы [ 4 ]

5 голосов
/ 02 августа 2020

Чтобы обойтись без блокировки, вы должны использовать std::vector<atomic_flag_wrapper>, где atomic_flag_wrapper обертывает std::atomic_flag аналогично коду в этом ответе .

With std::vector<bool> вы должны использовать блокировку , стандарт явно говорит вам об этом:

Несмотря на [res.on.data.races], необходимы реализации, чтобы избежать гонки данных, когда содержимое объекты, содержащиеся в разных элементах одного контейнера, за исключением vector<bool>, изменяются одновременно.

http://eel.is/c++draft/container.requirements.dataraces#2 (черновик C ++, 02.08.2020), курсив у меня

На простом английском языке sh:

std::vector<bool> не требует не нужно убедиться, что запись в два разных элемента не требует гонки; следовательно, может возникнуть гонка за данными; поэтому вам нужна блокировка.

Если бы это был, например, std::vector<char>, то стандарт гарантирует, что charVector[0] и charVector[1] могут быть записаны одновременно. Но все же вы не можете писать в charVector[0] одновременно из более чем одного потока; вам необходимо использовать атомикс .

std:atomic<bool> не гарантируется без блокировки, поэтому вам следует использовать std::atomic_flag с этой гарантией. Однако вы не можете поместить их в std::vector, потому что они не могут быть созданы копированием. Для этого вам понадобится оболочка, как описано в этом ответе .

3 голосов
/ 02 августа 2020

Вы должны использовать замок. На некоторых платформах это может быть ненужным, в то время как на других необходимо получить правильную функциональность из-за природы std::vector<bool>.

std::vector<bool> предназначен для экономии места, а элементы хранятся в отдельных битах. Если один поток записывает в boolvec[3], а другой - в boolvec[4], оба изменят один и тот же байт в памяти. Для этого требуется блокировка, чтобы гарантировать, что правильное значение будет видимым для всех потоков из-за цикла чтения-изменения-записи, необходимого для изменения значения. Без блокировки на некоторых платформах первая запись может быть не сразу видна для всех процессоров / ядер / потоков, в результате чего вторая запись будет использовать устаревшее значение, эффективно отменяя запись предыдущего потока на тот же адрес.

1 голос
/ 02 августа 2020

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

0 голосов
/ 02 августа 2020

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

...