2012-06-21 2 views
4

Я работаю над проектом на C++, который использует самосозданные карты для хранения данных - карты в этом смысле будут больше похожими на «географическую» карту, поэтому изображение. Есть разные темы чтения и записи на него. Данные карты хранятся в векторе std векторов целых чисел. Его размер не изменяется, а только содержание определенных пикселей через функции getter и setter.многопоточный вектор

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

+0

Вы должны использовать 1D-вектор. Он работает лучше, чем 2D. – chris

+1

Атомные операции могли бы сделать трюк, видя, как вы говорите: «размер не изменяется, а только содержание определенных пикселей через функции геттера и сеттера». Кроме того, попробуйте «разделить» доступ (т. Е. Разные потоки не изменяют одинаковые пиксели одновременно), чтобы минимизировать отравление кэша. Конечно, это не гарантирует, что два соседних пикселя согласованы друг с другом, но тогда блокировка не гарантирует этого, если вы измените их хаотичным способом. Тем не менее, он гарантирует, что, например, значение, которое увеличивается и уменьшается одновременно, не получает «странный» результат. – Damon

+0

@Damon: Я полагаю, что модель памяти, определенная в C++ 11, предназначена для того, чтобы такие эффекты, как вы описываете со смежными пикселями, не произошли. См. [Здесь] (http://stackoverflow.com/questions/6319146/). –

ответ

6

Вам понадобится блокировка. Чтобы это не повредило вашу производительность слишком сильно, вы должны попытаться сделать объем замков как можно меньше. Например, вы можете заблокировать отдельные строки-векторы, чтобы записи в разных строках не мешали друг другу. Какое решение наиболее подходит для вас, зависит от ваших шаблонов доступа и платформы.

+0

Большое спасибо. Я попытаюсь заблокировать только небольшую часть моего вектора для записи - нужно ли мне также блокировать его в операторе чтения? –

+0

Это зависит от того, что вы хотите делать с данными. Если вы только читаете, вам не нужен замок. Если вы читаете из региона, на котором написано, вам нужен замок, но тогда вы можете использовать [Readers-Writer Lock] (http://en.wikipedia.org/wiki/Readers-writer_lock). Возможно, в вашем сценарии вы даже можете жить без блокировки, если у вас есть только один писатель - вы иногда можете читать непоследовательные данные, но в зависимости от того, что вы делаете с ним, это может быть или не быть проблемой. –

0

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

Рассмотрите и пример. Представьте, что у вас есть стена, и вы хотите, чтобы она была окрашена в черные и белые полосы. И чтобы ускорить работу, вы решаете нанять двух сотрудников.

Теперь вы можете выделить это задание двумя способами. 1. Присвойте живопись черным полосам одному работнику и белому другому работнику. 2. Разделите стену на две части и назначьте левую перегородку одному работнику, а правую часть - второму работнику

Теперь, какая из них, вероятно, даст лучшую производительность?

В общем случае 2-й вариант лучше, так как рабочая зона рабочего хорошо отделяется, и нет необходимости ждать, пока другой выполнит свою работу. Конечно, 1-й подход не ошибается, но возможно, что один работник рисует в каком-то месте, а второй парень может также попасть в одно и то же место и должен будет дождаться завершения первого. Теперь представьте, что произойдет, если бы у вас было 10 рабочих, каждая из которых рисует только один особый цвет.

Многопотоковое программирование аналогично. Если вы можете лучше разбить данные проблемы, вы можете эффективно работать с потоками.

+0

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

0
  1. Использование легких замков. То есть на окнах используется «CriticalSection». Или напишите свои собственные блокировки пользовательского пространства, например. как в TinyThread (http://tinythreadpp.bitsnbites.eu/). Они написаны в ASM и должны иметь почти нулевые накладные расходы, чтобы фактически блокировать и разблокировать.

  2. Как только вы уверены, что сами замки бывают быстрыми, если все еще работает медленно, это связано с тем, что у вас есть конфликт. Например. несколько потоков, которым необходимо блокировать один и тот же ресурс. В вашем примере использования рассмотрим что-то вроде мьютекса «чтение/запись». Это класс, который будет иметь мьютекс чтения и мьютекс записи. Метод «readLock» на мьютексе блокирует только несколько циклов, чтобы увеличить счетчик ссылок на мьютекс. «readUnlock» уменьшает счетчик ссылок. «writeLock» блокирует прочитанный мьютекст и устанавливает флаг, который заставляет читателей блокировать мьютексы чтения. А затем блокирует мьютексы записи и выполняет операцию записи.Таким образом, вы гарантируете, что за один раз может произойти только одна операция записи, и что во время записи никакие чтения не могут произойти. Но допускается одновременное чтение.

+0

Ваш второй вариант звучит скорее как блокировка чтения/записи, тогда как вы можете иметь много одновременных чтений, взаимоисключающих с одной записью. http://en.wikipedia.org/wiki/Read/write_lock_pattern – Brady

+0

Да. Это и есть. Неправильно ли это назвать мьютексом чтения/записи? Все операции записи являются взаимоисключающими. –

+0

Я бы не сказал, что это неправильно, но его чаще называют блокировкой чтения/записи. – Brady

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