Правильный способ реализовать потокобезопасный метод в C ++ 11 - PullRequest
2 голосов
/ 17 декабря 2011

У меня есть класс, представляющий различные виды инструментов (GCC, LEX, YACC, ...). Каждому экземпляру присваивается тип, представляющий инструмент, и допускается специальная настройка.

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

int Tool::addType(std::string typeName,
        std::string typeFlagName)
    throw (GP::Exceptions::LockAcquisitionException)
{   
    static std::timed_mutex mutex;
    std::unique_lock<std::timed_mutex> lock{mutex};

    int typeId = 0;

    if (lock.try_lock_for(std::chrono::microseconds(100)))
    {   
        int typeId = typeNames.size();
        typeNames[typeId] = typeName;
        typeFlagNames[typeId] = typeFlagName;
    }   
    else
    {   
        throw GP::Exceptions::LockAcquisitionException{"Unable to generate new type ID within 100 microseconds."};
    }   
    return typeId;
}

Я хотел бы знать, является ли это хорошим решением или я что-то пропустил. Если это нормально, есть ли другое решение, менее подробное?

Ответы [ 2 ]

4 голосов
/ 17 декабря 2011

Почему бы не что-то подобное?

class tool
{
    std::atomic<int> index_;
    std::array<std::pair<std::string, std::string>, 2048> types_; // Should be more than enough room.

    int addType(std::string typeName, std::string typeFlagName)
    {   
        int id = index++;

        if(id >= types_.size())
            throw GP::Exceptions{"To many types."};

        types_[id] = std::make_pair(typeName, typeFlagName);

        return id;
    }

};

Вы можете сделать это немного умнее, используя std :: vector, и иметь блокировку только тогда, когда ее нужно перераспределить для большего размера.

ПРИМЕЧАНИЕ: предложение throw () устарело в C ++ 11.

3 голосов
/ 17 декабря 2011

Мое предложение будет:

class tool
{ 
   std::mutex myMutex;

   std::vector<std::string> typeNames;   

   int addType(std::string typeName)
   {
       std::lock_guard myLock(myMutex);
       typeNames.push_back(typeName);
       return typeNames.size()-1; // 
   }

   // Only hold lock when needed
   void longComplexFunction(int f)
   {
       // Compute as much as possible before
       int complexMagic = veryLongFunction(f);

       {
          std::lock_guard myLock(myMutex);
          typeNames[complexMagic] += "s";
       }
   }

}
...