Есть несколько способов, которыми функция может быть поточно-ориентированной.
Может быть реентерабельным . Это означает, что функция не имеет состояния и не затрагивает глобальные или статические переменные, поэтому ее можно вызывать из нескольких потоков одновременно. Термин происходит от разрешения одному потоку войти в функцию, в то время как другой поток уже находится внутри нее.
Может иметь критическую секцию . Этот термин часто используется, но, честно говоря, я предпочитаю критические данные . Критическая секция возникает каждый раз, когда ваш код касается данных, которые совместно используются несколькими потоками. Поэтому я предпочитаю сосредоточиться на этих важных данных.
Если вы правильно используете mutex , вы можете синхронизировать доступ к критически важным данным, должным образом защищая от небезопасных модификаций потока. Мьютексы и замки очень полезны, но с большой силой приходит большая ответственность. Вы не должны блокировать один и тот же мьютекс дважды в одном и том же потоке (это самоблокировка). Вы должны быть осторожны, если приобретаете более одного мьютекса, так как это увеличивает риск тупика. Вы должны постоянно защищать свои данные мьютексами.
Если все ваши функции являются поточно-ориентированными и все ваши общие данные защищены должным образом, ваше приложение должно быть поточно-ориентированным.
Как сказал Сумасшедший Эдди, это огромный вопрос. Я рекомендую читать в буст-потоках и использовать их соответствующим образом.
Предупреждение низкого уровня : компиляторы могут переупорядочивать операторы, что может нарушить безопасность потоков. С несколькими ядрами каждое ядро имеет свой собственный кеш, и вам необходимо правильно синхронизировать кеш, чтобы обеспечить безопасность потоков. Кроме того, даже если компилятор не переупорядочивает операторы, аппаратное обеспечение может. Таким образом, полная, гарантированная безопасность потоков сегодня на самом деле невозможна. Тем не менее, вы можете получить 99,99% пути, и сейчас ведется работа с поставщиками компиляторов и производителями процессоров, чтобы исправить эту давнюю оговорку.
В любом случае, если вы ищете контрольный список, чтобы сделать класс потокобезопасным:
- Определите любые данные, которые являются общими для всех потоков (если вы пропустите их, вы не сможете защитить их)
- создайте элемент
boost::mutex m_mutex
и используйте его всякий раз, когда вы пытаетесь получить доступ к этим данным общего члена (в идеале общие данные являются частными для класса, поэтому вы можете быть более уверены, что защищаете их должным образом).
- очистить глобалы. Глобалы в любом случае плохи, и удачи в попытках сделать что-нибудь с потоками безопасным для глобальных потоков.
- Остерегайтесь ключевого слова
static
. На самом деле это не потокобезопасно. Так что, если вы пытаетесь сделать синглтон, он не будет работать правильно.
- Остерегайтесь парадигмы блокировки с двойной проверкой. Большинство людей, использующих его, неправильно понимают его, и оно может быть нарушено из-за низкого уровня предупреждения.
Это неполный контрольный список. Я добавлю больше, если подумаю, но, надеюсь, этого достаточно, чтобы вы начали.