#c #multithreading #thread-safety
#c #многопоточность #потокобезопасность
Вопрос:
У меня есть анимационная программа на основе таймера, которую планировалось запустить в рабочем потоке. Программа была разработана для постоянной работы при запуске. У меня также есть поток создания изображений, который отвечает за обработку изображений, а затем передает каждое обработанное изображение (в формате JPEG / PNG) в поток анимации, чтобы принять участие в цикле изображения без вмешательства пользователя.
Это типичная программа для создания циклов изображений на основе памяти. То есть все выбранные пользователем изображения загружаются в оперативную память заранее. Я использую контейнер map для управления последовательностью изображений, объявленной в формате std::map, который связывает имена файлов изображений типа Key с указателями CBitmap типа Data. Я также использую векторную строку (объявленную как std::vector), чтобы сохранить копию списка файлов изображений в отсортированном порядке, соответствующем вышеупомянутому списку ключей карты, чтобы повторять каждое изображение по порядковому номеру. Возможно, в этом нет необходимости.
Что касается управления анимацией, разрешены следующие операции, подобные kiosk (некоторые сопровождаются объявлениями соответствующих переменных):
bool m_bPlay; // Play forward
bool m_bPause; // Pause animation
bool m_bStop; // Stop animation
bool m_bReverse; // Play backward
bool m_bRepeat; // Repeated play when reaching to last image
DWORD m_dwFrom; // Starting image number
DWORD m_dwTo; // Ending image number
DWORD m_dwCurrent; // Current image number
DWORD m_dwFPS; // Frames per second
Где переменная m_dwTo может быть изменена пользователем с помощью кнопки вращения, встроенной в панель инструментов, размещенную в верхней части главного окна GUI, или автоматически увеличиваться приложением каждый раз, когда новое обработанное изображение добавляется в вышеупомянутую карту, а также векторные контейнеры. Аналогично, переменная m_dwFrom также может быть изменена вручную таким же образом, как и m_dwTo, или автоматически уменьшена приложением всякий раз, когда срок действия одного или более изображений в воспроизведении истекает на основе пользовательской конфигурации текущего архива (например, сохранять изображения в течение 3 дней), и в то же время просроченные изображения следует удалять из вышеупомянутых картографических и векторных контейнеров. Переменная m_dwFPS может быть изменена пользователем в любое время в процессе зацикливания изображения с помощью выпадающего списка, встроенного в панель инструментов, расположенную в верхней части главного окна GUI.
Спасибо, что нашли время прочитать длинное объяснение, которое я хочу сделать. Я надеюсь, что это поможет вам ответить на мои следующие вопросы:
- Для того, чтобы сделать m_dwFrom, m_dwTo, m_dwCurrent и m_dwFPS потокобезопасными, является ли использование InterlockedExchange или InterlockedCompareExchange более эффективным и увеличивающим производительность, чем использование других блокировок, таких как CriticalSection, Мьютекс и т.д.?
- Как сделать std::map и std::vector потокобезопасными? Использовать только традиционные блокировки или лучше в сочетании с барьером изменения порядка компилятора (например, _ReadWriteBarrier для визуального C ) и / или барьером изменения порядка процессора (например, MemoryBarrier семейства процессоров x86 и x64)?
Я с нетерпением жду ваших предложений. Кодовые или ложные фрагменты кода высоко ценятся. Заранее благодарю вас!
Голден Ли
Комментарии:
1. Извините, я повторю свой второй вопрос: 2. Как сделать std::map<std::string, CBitmap*> и std::vector<std::string> потокобезопасными? Использовать только традиционные блокировки или лучше в сочетании с барьером изменения порядка компилятора (например, _ReadWriteBarrier для визуального C ) и / или барьером изменения порядка процессора (например, MemoryBarrier семейства процессоров x86 и x64)? <br/>
Ответ №1:
Возможно, я ошибаюсь, но, насколько я могу догадаться из вашего описания, я бы выбрал традиционные блокировки и мьютексы, чтобы сделать ваш общий вектор и карту, а также другие ваши общие переменные потокобезопасными. Это просто самый простой способ, и ваш сценарий на самом деле не требует такой высокой производительности, чтобы оправдывать что-то более сложное. Я бы затронул что-нибудь более необычное, только если профилирование покажет, что традиционная блокировка становится проблемой производительности!
Как сделать std::map и std::vector потокобезопасными?
Обычный способ сделать это — просто написать блокирующую оболочку вокруг функций контейнера, к которым вам нужен доступ. Например:
class myAnimationManager{
private:
std::map<std::string, CBitmap*> m_imagesMap;
Mutex m_mutex;
public:
CBitmap * getImageByName(const std::string amp; _name)
{
ScopedLock l(m_mutex); //lock image map access
return m_imagesMaps[_name];
}
//...
};
Преимуществом использования стандартных примитивов блокировки является не только простота, но и переносимость, например, при использовании boost::thread.
Комментарии:
1. Спасибо, Мока, за твой ответ на мой вопрос 2. Я закончил свой проект simple animation в прошлом году. Но он несколько раз выходил из строя в течение 7X24 года подряд. Мой репозиторий анимации std::map<std::string, CBitmap*> может быть наиболее подозрительным объектом, вызывающим сбой приложения. Итак, это основная цель моего второго вопроса, который был задан на SO. Кстати, я использовал CriticalSection, чтобы предотвратить состояние гонки чтения / записи кадров анимации.