【发布时间】:2021-07-30 19:45:20
【问题描述】:
我有一堂课:
class IOWorker {
std::thread thread_;
boost::asio::io_service ios_;
boost::optional<boost::asio::io_service::work> work_;
Callback callback_;
// Map of thread::id and this class' instance
typedef std::map<std::thread::id, IOWorker *> IOWorkerThreadMap;
static IOWorkerThreadMap iOWorkerThreadMap;
public:
IOWorker(Callback cb);
~IOWorker();
std::thread::id getThreadId() {
return thread_.get_id();
}
// IO worker threads will call this to fetch their instance
static IOWorker* getIOWorkerInstance (void) {
auto it = iOWorkerThreadMap.find(std::this_thread::get_id());
if (it == iOWorkerThreadMap.end()) {
return nullptr;
}
return (it->second);
}
};
IOWorker::IOWorker (Callback cb) : callback_{cb}
{
work_ = boost::in_place(boost::ref(ios_));
thread_ = std::thread{[this] () {
ios_.run();
}
};
}
在主线程执行的函数中,我创建了 10 个此类的实例并将它们插入到映射中,其中 thread::id 是键,class 实例是值。
我正在从所有工作线程访问此映射,以通过在映射中查找它们的 thread::id 来获取它们各自的 class 实例。主线程也访问这些实例,调用一些方法,在 ios_ 上发布作业等。
void startIOWorkers (Callback cb)
{
for (int i = 0; i < 10; ++i) {
IOWorker *iow = new IOWorker{cb};
std::thread::id threadId = iow->getThreadId();
IOWorkerThreadMap.insert(std::make_pair(threadId, iow));
}
}
我的问题是针对以下行:
IOWorkerThreadMap.insert(std::make_pair(threadId, iow));
我的理解(可能是错误的!)是上述函数中的iow 和threadId 在我将它们插入地图时将被“复制”,并且它们的两个副本将存在。
我想避免这种情况,因此,我想知道在这种情况下拥有thread::id 和class 实例的映射的更好方法是什么?
【问题讨论】:
-
是我遗漏了什么,还是仅仅使用
thread_local IOWorker* this_thread_worker;会简单得多? -
您的代码没有显示同步,以确保两个或多个线程不会同时访问静态地图。
-
@PaulMcKenzie,它在原始代码中得到了照顾。删除它以减少“示例”中的混乱。甚至类定义也大大缩短了。
-
那么我不明白为什么创建地图条目会是一个问题。如果一切都是同步的,我看不出你声称的任何问题可能是一个问题。那么,如果制作了副本会怎样(这就是基于价值的容器的工作方式)。
-
当然会有两份。但是,如果本地版本无论如何都会超出范围,会有什么问题呢?对于在映射、向量、std::list 等中插入值的任何 C++ 代码,您不妨提出此问题。