Когда вызов размера очереди не безопасен? - PullRequest
1 голос
/ 29 февраля 2020

Как правило, операции со стандартными контейнерами не безопасны для потоков ( в основном ). Вызов size для std::vector, например, может завершиться ошибкой , когда происходит перераспределение.

Поскольку dequeue не перераспределяет и не перемещает элементы , как это делает стандартный вектор, существуют ли условия, при которых вызов size в очереди может быть небезопасным? Наиболее вероятный сценарий, по-видимому, возникает при добавлении / удалении элементов в другом потоке, когда выполняется вызов size, но, поскольку доступ к целому числу в большинстве случаев безопасен , у меня возникают проблемы при мысли о том, как вызывать size из отдельного потока будет проблематично c.

Ответы [ 2 ]

3 голосов
/ 29 февраля 2020

Всегда . Потому что в любом стандарте этого не требуется.

Реализация G CC здесь https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_deque.h является результатом вычитания:

      // [23.2.1.2] capacity
      /**  Returns the number of elements in the %deque.  */
      size_type
      size() const _GLIBCXX_NOEXCEPT
      { return this->_M_impl._M_finish - this->_M_impl._M_start; }

Чет если размер был сохранен в size_t или даже uint8_t, а size() были встроенной функцией, возвращающей эту переменную, C ++ не дает никаких гарантий об атомарности различных целых чисел. Никогда не думайте, что что-то является потокобезопасным, если это не гарантировано.

0 голосов
/ 29 февраля 2020

Например, вот так

std::deque<int> dq;
dq.push_back(1);

// thread0
void printElementIfExist() {
    if (dq.size() > 0) {
        std::cout << dq[0] << std::endl;
    }
}
// thread1
void removeElementFromDeque() {
    if (dq.size() > 0) {
        dq.pop_back();
    }
}

условие гонки может позволить получить доступ к dq[0], который уже освобожден.

Вернуться к самому вызову size(). Существуют архитектуры, в которых операция чтения не является атомом c.

...