我有以下层次结构:
struct Point
{
std::atomic<int> x;
std::atomic<int> y;
std::atomic<int> z;
}
class Data
{
std::atomic<int> version;
Point point;
}
unordered_map<std::string,Data> hashtable; // global
Thread1是制作人:
线程1收到std::pair<std::string,Point> new_data
,它确实:
shared_hashtable[new_data.first].point.x.store(new_data.second.x,memory_order_release) // update X
shared_hashtable[new_data.first].point.y.store(new_data.second.y,memory_order_release) // update Y
shared_hashtable[new_data.first].point.z.store(new_data.second.z,memory_order_release) // update Z
hashtable[new_data.first].version.store(hashtable[new_data.first].version+1,memory_order_release) // update the version of the data
线程2:
int local_version;
while(local_version!=shared_hashtable["string1"].version.load(memory_order_acquire))
{
//...process data...
local_version=shared_hashtable["string1"].version.load(memory_order_acquire);
}
传递的内存顺序是否保证我的存储和加载不会被重新排序。
设计是否按预期工作:如果hastable["string1"]
处的对象更新,我是否会处理线程2中的相应数据?
答案 0 :(得分:2)
hashtable
未受到同步访问保护,其operator[]
不是const
。如果您保证在这两个线程尝试访问它之前将(1)hashtable["string1"]
插入到表中,并且(2)在这两个线程运行期间没有其他线程写入hashtable
, hashtable
中的查找不会导致数据竞争。如果您不能保证(1)和(2),那么您需要使用互斥锁保护查找。 unordered_map
在重新哈希时使迭代器无效,但引用保持有效,直到从地图中删除引用的项目。
内存模型保证,在memory_order_release
从version
读取memory_order_acquire
中的相应值之后,线程2中可以看到线程1中写入version
写入Point
之前的写入。 }。即使对Point
成员的访问是非原子的,也是如此。
但是,线程2中Point
成员的读取可能会在线程1中看到以后写入的值,因此不能保证三个{{1}在线程2中读取的成员对应于线程1实际写入的特定Point
。我想你需要保证线程2处理的Point
实际上是Point
由线程1编写而不是多个不同点的值的集合(例如,版本1的x
,版本2的y
,版本3的z
。改变设计
struct Point { atomic<int> x, y, x; };
到
struct Point { int x, y, x; };
struct Data {
atomic<int> version;
atomic<Point> point;
};
将确保Point
读取实际上是Point
。当然,它不一定是Point
对应于给定的version
:point
可能已经被线程1中的以后的版本覆盖了线程2到处读取它的时间。这可能导致同一点被线程2处理两次,一次使用陈旧版本,再次使用适当版本再次处理。如果您需要确保每个版本最多只处理一次,则必须验证{<1}}在读取version
之后是,因为它是之前> em>阅读point
。
总而言之,我们得到了这个程序(DEMO):
point
答案 1 :(得分:1)
你可以试试 https://github.com/Taymindis/atomic_hashtable
用于读取,写入和删除的哈希表,而不进行锁定,而多线程在缓冲区上执行操作,简单和稳定
Readme.md中提供的API文档