我的想法是为每个线程提供实例,因此我为每个新的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);
}
这是个好主意吗?
答案 0 :(得分:2)
不,不是个好主意。
std::map
方法本身不是线程安全的。
为了真正使其成为一个好主意&#34;,您还必须使用互斥锁或同等产品来访问std::map
线程安全的所有权限。
这不仅包括您已注释掉的部分,还包括您正在使用的所有其他方法,例如find
()。
触及std::map
的所有内容都必须受互斥保护。
答案 1 :(得分:2)
在您访问地图后进行互斥锁定是不够的。您无法在没有互斥锁的情况下到达地图附近的任何位置,因为在您从中读取地图时,另一个线程可能会使用互斥锁来修改地图。
{
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
有点难以发现,但线程&#9; 9200已分配..4a80 ..而线程&#39; 1904已分配..4b00 ..