c++ - 在 map 中使用 std::thread::id 以获得线程安全

标签 c++ multithreading

想法是为每个线程创建一个实例,所以我为每个新的 thread::id 创建了一个新的实例:

struct doSomething{
    void test(int toto) {}
};

void test(int toto)
{
    static std::map<std::thread::id, doSomething *> maps;

    std::map<std::thread::id, doSomething *>::iterator it = maps.find(std::this_thread::get_id());
    if (it == maps.end())
    {
        // mutex.lock() ?
        maps[std::this_thread::get_id()] = new doSomething();
        it = maps.find(std::this_thread::get_id());
        // mutex.unlock() ?
    }
    it->second->test(toto);
}

这是个好主意吗?

最佳答案

在访问 map 后拥有互斥锁是不够的。如果没有互斥量,您就不能靠近 map ,因为在您读取 map 时,另一个线程可能会使用互斥量来修改 map 。

{
    std::unique_lock<std::mutex> lock(my_mutex);
    std::map<std::thread::id, doSomething *>::iterator it = maps.find(std::this_thread::get_id());
    if (it != maps.end())
        return *it;
    auto ptr = std::make_unique<doSomething>();
    maps[std::this_thread::get_id()] = ptr.get();
    return ptr.release();
}

但除非您有一些特殊/独特的用例,否则这是一个已经通过 thread-local storage 解决的问题, 因为你有 C++11 你有 thread_local storage specifier .

请注意,我在这里使用了 mutex,因为 cout 是共享资源,而 yield 只是为了鼓励更多的交错工作流程。

#include <iostream>
#include <memory>
#include <thread>
#include <mutex>

static std::mutex cout_mutex;

struct CoutGuard : public std::unique_lock<std::mutex> {
    CoutGuard() : unique_lock(cout_mutex) {}
};

struct doSomething {
    void fn() {
        CoutGuard guard;
        std::cout << std::this_thread::get_id() << " running doSomething "
            << (void*)this << "\n";
    }
};

thread_local std::unique_ptr<doSomething> tls_dsptr; // DoSomethingPoinTeR

void testFn() {
    doSomething* dsp = tls_dsptr.get();
    if (dsp == nullptr) {
        tls_dsptr = std::make_unique<doSomething>();
        dsp = tls_dsptr.get();
        CoutGuard guard;
        std::cout << std::this_thread::get_id() << " allocated "
            << (void*)dsp << "\n";
    } else {
        CoutGuard guard;
        std::cout << std::this_thread::get_id() << " re-use\n";
    }
    dsp->fn();
    std::this_thread::yield();
}

void thread_fn() {
    testFn();
    testFn();
    testFn();
}

int main() {
    std::thread t1(thread_fn);
    std::thread t2(thread_fn);
    t2.join();
    t1.join();
}

现场演示:http://coliru.stacked-crooked.com/a/3dec7efcb0018549

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
140551597459200 allocated 0x7fd4a80008e0
140551597459200 running doSomething 0x7fd4a80008e0
140551605851904 allocated 0x7fd4b00008e0
140551605851904 running doSomething 0x7fd4b00008e0
140551605851904 re-use
140551605851904 running doSomething 0x7fd4b00008e0
140551597459200 re-use
140551605851904 re-use
140551597459200 running doSomething 0x7fd4a80008e0
140551605851904 running doSomething 0x7fd4b00008e0
140551597459200 re-use
140551597459200 running doSomething 0x7fd4a80008e0

有点难以发现,但线程 '9200 分配了 ..4a80.. 而线程 '1904 分配了 ..4b00..

关于c++ - 在 map 中使用 std::thread::id 以获得线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31094021/

相关文章:

android - 使用 Qt for Android 在 Android 中显示网页

java - 在方法中使用 'var' 是否会使执行(并发)线程不安全?

c# - 多线程时将参数传递给方法

c++ - 运行时错误-f1.exe 不存在或不是可执行文件

python - 为什么python线程会消耗这么多内存?

c++ - 检查结构是否不在 vector 中

c++ - 从类模板生成 lambda

Java SNMP4J 陷阱应用程序正在卡住 GUI

c++ - 什么 Linux 库支持套接字、ioctl 调用、tuntap 等...?

c++ - Qt C++ 从另一个类访问窗口方法