C++ C++;线程安全映射

C++ C++;线程安全映射,c++,dictionary,collections,thread-safety,stdmap,C++,Dictionary,Collections,Thread Safety,Stdmap,有人知道我在哪里可以找到一个封装std::map并使其线程安全的实现吗?当我说线程安全时,我的意思是它只提供对映射的串行访问,一次一个线程。最佳情况下,此映射应仅使用标准库和/或boost结构。boost共享互斥体将提供最佳的多读取器/单写入器方法来包装给定约束的标准映射。我不知道有哪种“预构建”实现能将这两者结合起来,因为这项任务通常很琐碎。这取决于要实现的应用程序。“线程安全”映射将对映射进行单独的线程安全调用,但许多操作需要跨调用进行线程安全的操作。使用映射的应用程序应将互斥体与映射相关联

有人知道我在哪里可以找到一个封装
std::map
并使其线程安全的实现吗?当我说线程安全时,我的意思是它只提供对映射的串行访问,一次一个线程。最佳情况下,此映射应仅使用标准库和/或boost结构。

boost共享互斥体将提供最佳的多读取器/单写入器方法来包装给定约束的标准映射。我不知道有哪种“预构建”实现能将这两者结合起来,因为这项任务通常很琐碎。

这取决于要实现的应用程序。“线程安全”映射将对映射进行单独的线程安全调用,但许多操作需要跨调用进行线程安全的操作。使用映射的应用程序应将互斥体与映射相关联,并使用该互斥体协调对它的访问


试图在java中实现线程安全容器是错误的,C++中的错误是错误的。

,集合类通常不能提供线程安全性,因为它们无法知道它们是如何被使用的。通过在使用集合的更高级别构造中实现自己的锁定机制,您将得到更好的服务。

试试这个库

它是在现代C++策略基础上实现的。 下面是从链接中截取的一些片段,以展示“向量”案例的想法

typedef lwsync::critical_resource<std::vector<int> > sync_vector_t;
sync_vector_t vec;

// some thread:
{
   // Critical resource can be naturally used with STL containers.
   sync_vector_t::const_accessor vec_access = vec.const_access();
   for(std::vector<int>::const_iterator where = vec_access->begin();
         where != vec_access->end();
         ++where;
        )
   std::cout << *where << std::endl;
}

sync_vector_t::accessor some_vector_action()
{
   sync_vector_t::accessor vec_access = vec.access();
   vec_access->push_back(10);
   return vec_access;
   // Access is escalated from within a some_vector_action() scope
   // So that one can make some other action with vector before it becomes
   // unlocked.
}

{
   sync_vector_t::accessor vec_access = some_vector_action();
   vec_access->push_back(20);
   // Elements 10 and 20 will be placed in vector sequentially.
   // Any other action with vector cannot be processed between those two
   // push_back's.
}
typedef lwsync::关键资源同步向量;
同步向量向量;
//一些线程:
{
//关键资源可以自然地与STL容器一起使用。
sync_vector_t::const_accessor vec_access=vec.const_access();
对于(std::vector::const_迭代器,其中=vec_access->begin();
其中!=vec_access->end();
++在哪里;
)
标准:不能向后推(20);
//元素10和20将按向量顺序放置。
//无法在这两个操作之间处理任何其他带有向量的操作
//向后推。
}

不符合您指定的标准,但您可以查看容器。所谓的
并发散列映射
允许多个线程并发访问映射中的数据。有一些细节,但所有内容都有很好的文档记录,可以让您了解“并发容器”。根据您的需要,这可能是完全不合适的…

您可能会看到我提出了这一点(我相信可以改进为接受两个以上的参数):

模板
类别组合:公共T1、公共T2
{
公众:
///我们总是需要一个虚拟析构函数。
虚拟~combine(){}
};
这允许您执行以下操作:

// Combine an std::mutex and std::map<std::string, std::string> into
// a single instance.
combine<std::mutex, std::map<std::string, std::string>> lockableMap;

// Lock the map within scope to modify the map in a thread-safe way.
{
    // Lock the map.
    std::lock_guard<std::mutex> locked(lockableMap);

    // Modify the map.
    lockableMap["Person 1"] = "Jack";
    lockableMap["Person 2"] = "Jill";
}
//将std::mutex和std::map组合到
//一个实例。
组合可锁地图;
//将映射锁定在范围内,以线程安全的方式修改映射。
{
//锁定地图。
std::锁定(锁定地图);
//修改地图。
可锁定地图[“人1”]=“杰克”;
可锁定地图[“人2”]=“吉尔”;
}

如果您希望使用std::recursive_互斥体和std::set,这也会起作用。

这里有一个建议(由我提供-无耻插件),它包装对象(包括
STL
容器),以实现高效(零成本)线程安全访问:

基本思想很简单。只有几个包装器类用于强制执行读/写锁定,同时提供包装对象的常量(只读)或非常量(读写)视图

其思想是使编译时不可能不正确地访问线程之间共享的资源

可在此处找到实现代码:


这项任务绝不是琐碎的,至少要有效地完成,这就是你找不到任何实现的原因。好吧,也许“琐碎”这个词是错误的。这并不难做到,至少在您正在处理的特定上下文中是如此(除非您有一些非常具体的需求)。如果容器符合大小/开始/结束/迭代和适当的复制/移动语义所期望的各种接口,那么这并不简单。仅仅使用映射以线程安全的方式存储和检索元素是一个好主意。为什么这不是一个好主意?你能给我指一些文章吗?我不明白为什么java、C++、/VB(.NET)和C++都有并发的库,如果它们是坏主意的话。这些库分别是:java.util.concurrent、System.Collections.concurrent(.NET 4.0)和Intel的线程构建块。是否有理由认为使用这些库只会影响性能?我知道有些集合总是返回一个快照“副本”用于迭代等等,所以我可以看出这样做的速度会慢一些。我不明白为什么那些库也有线程安全的集合。他不是在要求线程安全的集合类。他想要一个“更高层次的构造”,正如你所说的“包装”实现。这个库依赖于Intel CPU吗?你能解释一下为什么制作线程安全容器是一个错误吗?我想,迟响应总比不响应好吧?我在Java中看到的一个常见错误模式是,在原始哈希表等(被认为是线程安全的)中,代码在循环前后对表进行迭代,而没有显式地锁定它。这使得其他线程可以同时访问该表。如果第一个线程(正在迭代的线程)或任何其他线程正在修改表,这将导致争用条件。我相信Hashtable被宣传为“线程安全设计”的事实鼓励了这种错误模式。这是一个有点胡说八道的解释。“线程安全”只是意味着在并发访问对象时不会出现数据损坏、崩溃等情况。这并不意味着没有竞争条件、交易或其他类似的东西。就像单线程安全集合不会以某种方式导致代码没有bug一样。有一些糟糕的程序员
// Combine an std::mutex and std::map<std::string, std::string> into
// a single instance.
combine<std::mutex, std::map<std::string, std::string>> lockableMap;

// Lock the map within scope to modify the map in a thread-safe way.
{
    // Lock the map.
    std::lock_guard<std::mutex> locked(lockableMap);

    // Modify the map.
    lockableMap["Person 1"] = "Jack";
    lockableMap["Person 2"] = "Jill";
}