在C ++ 11中实现线程安全方法的正确方法

时间:2011-12-17 16:03:09

标签: c++ multithreading locking c++11 mutex

我有一个代表不同类型工具的类(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 个答案:

答案 0 :(得分:4)

为什么不喜欢?

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使它变得更聪明,只有在需要重新分配更大的大小时才能锁定。

注意:在C ++ 11中不推荐使用throw()子句。

答案 1 :(得分:3)

我的建议是:

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";
       }
   }

}