首页 > 解决方案 > 从多个线程修改 unordered_map 是否安全?

问题描述

我知道有 C++ 并发 hashmap 库,例如folly。然而,天下没有免费的午餐。如果我只使用原生 STL 容器,例如 unordered_map。

示例代码有三个版本:

第一个版本:

#include "boost/asio/thread_pool.hpp"
#include "boost/thread.hpp"
#include "boost/asio.hpp"
#include <thread>
#include <unordered_map>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>

int main() {
    // boost::asio::thread_pool pool(std::thread::hardware_concurrency());
    boost::asio::thread_pool pool(1);
    std::unordered_map<int, int> students;
    srand((unsigned)time(NULL));
    // std::mutex m;
    for(int i = 0; i < 10000; i++) {
        // boost::asio::post(pool, [&students, &m] () {
        //     std::lock_guard<std::mutex> lock(m);
        boost::asio::post(pool, [&students] () {
            students.emplace(std::make_pair(rand(), rand()));
        });        
    }
    pool.join();
    for(auto item : students) {
        std::cout << item.first << " " << item.second << std::endl;
    }
    std::cout << students.size() << std::endl;

    return 0;
}

在第一个版本中,只有一个线程。所以没有任何问题。

第二个版本:

#include "boost/asio/thread_pool.hpp"
#include "boost/thread.hpp"
#include "boost/asio.hpp"
#include <thread>
#include <unordered_map>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>

int main() {
    boost::asio::thread_pool pool(std::thread::hardware_concurrency());
    // boost::asio::thread_pool pool(1);
    std::unordered_map<int, int> students;
    srand((unsigned)time(NULL));
    std::mutex m;
    for(int i = 0; i < 10000; i++) {
        boost::asio::post(pool, [&students, &m] () {
            std::lock_guard<std::mutex> lock(m);
        // boost::asio::post(pool, [&students] () {
            students.emplace(std::make_pair(rand(), rand()));
        });        
    }
    pool.join();
    for(auto item : students) {
        std::cout << item.first << " " << item.second << std::endl;
    }
    std::cout << students.size() << std::endl;

    return 0;
}

在第二个版本中,可能会有多个线程将数据插入到一个 unordered_map 中,线程的数量取决于机器。在将数据插入 unordered_map 之前,有一个锁保证一次只有一个线程可以插入 unordered_map。第二个版本也没有任何问题。

第三个版本:

#include "boost/asio/thread_pool.hpp"
#include "boost/thread.hpp"
#include "boost/asio.hpp"
#include <thread>
#include <unordered_map>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <time.h>

int main() {
    boost::asio::thread_pool pool(std::thread::hardware_concurrency());
    // boost::asio::thread_pool pool(1);
    std::unordered_map<int, int> students;
    srand((unsigned)time(NULL));
    // std::mutex m;
    for(int i = 0; i < 10000; i++) {
        // boost::asio::post(pool, [&students, &m] () {
        //     std::lock_guard<std::mutex> lock(m);
        boost::asio::post(pool, [&students] () {
            students.emplace(std::make_pair(rand(), rand()));
        });        
    }
    pool.join();
    for(auto item : students) {
        std::cout << item.first << " " << item.second << std::endl;
    }
    std::cout << students.size() << std::endl;

    return 0;
}

在第三个版本中,多个线程将数据插入到一个 unordered_map 中。代码可以编译成功。但是,在运行相应的可执行程序时,控制台会打印“Segmentation fault (core dumped)”

在 C++11 中同时从多个线程修改 unordered_map(STL 容器)是否安全?

如果不安全,是否有任何意外的不安全行为或预期的不安全行为,不安全行为的原因是什么?

除了开源并发哈希映射库和第一版代码和第二版代码,还有其他解决方案可以在C++11中安全地从多个线程同时修改unordered_map(STL容器)吗?

标签: c++multithreadingstl

解决方案


推荐阅读