2015-01-26 5 views
3

У меня есть std::map<int, object*>, который мне нужен для доступа (чтения и записи) из разных тем. Конечно, я могу просто использовать один критический раздел для чтения и записи, но он будет иметь огромное влияние на производительность, потому что у меня есть много find() звонков (несколько тысяч в секунду) и значительно меньше записей (как правило, одна вставка и один стирать при создании и уничтожении потока).потокобезопасное использование std :: map

Поэтому для записи нужно использовать CriticalSection и проверять только, если другой поток выполняет операцию записи перед чтением. Но как? Я нашел решения для C++ 11 и boost, но я использую Visual Studio 2008 (из-за проблем с совместимостью).

Может ли кто-нибудь дать мне пример или объяснение того, как это сделать? Благодаря!

+4

В Windows API для Vista или более поздних версий есть также блокировки чтения/записи. https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937(v=vs.85).aspx –

ответ

0

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

В Windows API есть mutex functions, чтобы зарегистрировать ручку мьютекса с системой. Ручка действует как способ для Windows распознавать мьютексы и проверять, ожидает ли она.

Вот простой класс mutex, чтобы вы начали использовать некоторые вызовы Windows API.

class MyMutex { 

    private: 
     HANDLE m_hMutex; 

    public: 
     MyMutex() 
     { 
      m_hMutex = CreateMutex(NULL, FALSE, NULL); 
     } 

     ~MyMutex() 
     { 
      CloseHandle(m_hMutex); 
     } 

     void Lock() 
     { 
      BOOL test = WaitForSingleObject(m_hMutex, INFINITE); 
     } 

     void UnLock() 
     { 
      ReleaseMutex(m_hMutex); 
     } 
}; 
0

Что вы ищете, это система блокировки нескольких считывателей/одиночной записи. К сожалению, для этого нет встроенного типа (до C++ 14). Если вы можете использовать boost, тогда вы можете пойти с boost shared_mutex

Если нет, вам придется сделать это самостоятельно (прочтите это other thread на SO). Вы также можете использовать блокировку MS SRW, как указано в комментарии T.C. (см. there).

Теперь предположим, что у вас есть класс shared_mutex, который хорошо определен и доступен. Вам просто нужно добавить один объект shared_mutex в качестве атрибута для класса, который вы хотите защитить. Я бы посоветовал вам держать полностью замок-бесплатные методы в классе и добавить обертки вокруг них, как это:

class Whatever; 
class MyClass { 
    boost::shared_mutex mutex; 
    Whatever find_unlocked() { 
     whatever blob_blob; 
     blob_blob = do_whatever_work_find_does(); 
     return blob_blob; 
    } 
    void write_smth_unlocked() { 
     do_something_that_needs_writing_to_MyClass(); 
    } 
public: 
    Whatever find() { 
     Whatever blob; 
     mutex.lock_shared(); // Locks for reading (shared ownership on the mutex) 
     blob = find_unlocked(); 
     mutex.unlock_shared(); 
     return blob; 
    } 
    void write_smth() { 
     mutex.lock(); // Locks for writing (exclusive ownership on the mutex) 
     write_smth_unlocked(); 
     mutex.unlock(); 
    } 
}; 

Это даст вам возможность повторного использования операции, которые определяют в новых функций для класса время все еще будучи в состоянии защитить все новые операции через систему блокировки.

В конце концов, вы бы два метода для любой операции вы определяете:

  • частный (или защищенный) метод: operation_unlocked()
  • Публичный один: operation() который использует shared_mutex.