我正在使用一个库,该库使用多线程在事件发生时调用成员函数。库中的每个"处理程序"都有一个可以调用函数MyClass::Process(const Signal& signal)
的线程。MyClass 引用了一个名为 cat
的Catalog
类。
在Process
里面,我有以下代码:
Stats stats;//simple container struct to hold values
std:string id(signal.signalId());
//set values of stats here based on the values in signal
cat->onSignalUpdate(id, stats);
从库的文档中:
在处理程序的单个实例的边界内不可能有两个 要同时调用的用户回调。但是,不同的 不同通道的处理程序实例未与每个通道链接 其他,因此来自不同处理程序实例的调用可能会 并行发生。
目录具有成员std::map<std::string, Stats> signal_map
Catalog::onSignalUpdate(const std::string& id, const Stats& stats)
内部
std::map<std::string, Stats>::iterator it(signal_map.find(id));
if(it != signal_map.end())
{
it->second = stats;
}
这在大部分情况下都有效,其中正确的 Id 映射到相应的统计信息结构。有时,我会遇到不正确的匹配,其中处理程序 A 的 ID 被分配给属于处理程序 B 的结构。在我看来,该函数是并行调用的。我的印象是,在线程中,对函数的调用虽然是并行完成的,但却是重复的。不是这种情况,还是在线程中通过引用传递值存在问题?
如果没有某种形式的保护,防止多个线程同时修改map
,则无法从多个线程更新std::map
。你需要一个互斥锁或类似的东西。特别是,如果id
是"新的",那么映射中的底层数据结构(通常是"RB树")将被更改。这不能从多个线程完成。在修改树时,您也无法访问树以"读取",因为树中的条目可能是"半更新"的(例如,下一个元素指向尚未正确填充的元素或类似元素)。