在书中C++ Concurrency in Action ,作者给出了一个使用hazard pointer实现无锁栈数据结构的例子。部分代码如下:
std::shared_ptr<T> pop()
{
std::atomic<void*>& hp=get_hazard_pointer_for_current_thread();
node* old_head=head.load();
node* temp;
do
{
temp=old_head;
hp.store(old_head);
old_head=head.load();
} while(old_head!=temp);
// ...
}
描述是这样说的
You have to do this in a
whileloop to ensure that thenodehasn’t been deleted between the reading of the oldheadpointer and the setting of the hazard pointer. During this window no other thread knows you’re accessing this particular node. Fortunately, if the oldheadnode is going to be deleted,headitself must have changed, so you can check this and keep looping until you know that theheadpointer still has the same value you set your hazard pointer to.
我认为代码有缺陷,因为 head 节点受制于 ABA problem .即使head的值保持不变,它原来指向的节点也可能已经被删除了。分配了一个新的head节点,它恰好与前一个节点具有相同的地址值。
最佳答案
默认memory_order load() 操作是 std::memory_order_seq_cst,它确保所有操作的顺序一致性(总体全局排序):
Each
memory_order_seq_cstoperationBthat loads from atomic variableM, observes one of the following:
- the result of the last operation
Athat modifiedM, which appears beforeBin the single total order- OR, if there was such an
A,Bmay observe the result of some modification onMthat is notmemory_order_seq_cstand does not happen-beforeA- OR, if there wasn't such an
A,Bmay observe the result of some unrelated modification ofMthat is notmemory_order_seq_cst.
因此,如果节点被修改(删除)并且这发生在第二次读取全局总顺序之前,您一定会看到该更改,因此循环将继续执行。如果此修改在之后进行,则不会有任何危害,因为已经设置了风险指针。
你有这个保证,因为存储到危险指针也是用 std::memory_order_seq_cst 完成的。此内存顺序为加载提供了一个获取操作,为存储提供了一个释放操作,从而防止在同一线程内重新排序。因此,“成功”读取 (old_head==temp) 保证保存了正确的数据。
将这两个负载视为同步点 - 因为它们执行 acquire 操作,所以它们与修改这些值的相应 release 操作同步,导致所有写入成为可见。
您描述的问题在任何方面都不会影响示例。 pop() 函数用于删除顶部元素,它会执行此操作。如果在此期间添加/删除元素,它将弹出它,无论它的地址是什么(它甚至可能与之前获取的地址相同)。这是一个完全不同的问题。考虑:
concurrent_stack<int> p;
if (!p.empty() && (p.top() == 5))
{
auto t = p.pop();
assert( t ); // May fail
assert( *t == 5 ); // May fail
}
这两个断言都可能失败,如果许多线程非常密集地使用堆栈,很可能会经常失败。但这不是由于 pop() 的错误实现,而是您需要更强的访问限制以确保确实从堆栈中删除最后检查的元素。
关于c++ - 这个危险指针示例是否因为 ABA 问题而存在缺陷?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48783613/
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查
我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您