标准中是否有任何措辞保证对原子的宽松存储不会被提升到互斥锁的锁定之上?如果没有,是否有任何措辞明确表示编译器或 CPU 这样做是符合犹太教规的?
例如,采用以下程序(它可能使用 acq/rel 来处理 foo_has_been_set 并避免锁定,和/或使 foo 本身原子化。它是这样写的来说明这个问题。)
std::mutex mu;
int foo = 0; // Guarded by mu
std::atomic<bool> foo_has_been_set{false};
void SetFoo() {
mu.lock();
foo = 1;
foo_has_been_set.store(true, std::memory_order_relaxed);
mu.unlock();
}
void CheckFoo() {
if (foo_has_been_set.load(std::memory_order_relaxed)) {
mu.lock();
assert(foo == 1);
mu.unlock();
}
}
如果另一个线程同时调用 SetFoo,CheckFoo 是否可能在上述程序中崩溃,或者是否可以保证存储到 foo_has_been_set 不能被编译器和 CPU 提升到对 mu.lock 的调用之上?
这与 an older question 有关,但我不是 100% 清楚那里的答案适用于此。特别是,该问题答案中的反例可能适用于对 SetFoo 的两个并发调用,但我对编译器知道有一个对 SetFoo<> 和一次对 CheckFoo 的调用。能保证安全吗?
我正在寻找标准中的具体引用。
最佳答案
我想我已经找到了保证 程序不能崩溃。在下面的答案中,我引用了 version N4659标准草案。
写线程A和读线程B涉及的代码是:
A1: mu.lock()
A2: foo = 1
A3: foo_has_been_set.store(relaxed)
A4: mu.unlock()
B1: foo_has_been_set.load(relaxed) <-- (stop if false)
B2: mu.lock()
B3: assert(foo == 1)
B4: mu.unlock()
我们寻求证明,如果 B3 执行,那么 A2 在 B3 之前发生,如 [intro.races]/10 中所定义。 .作者 [intro.races]/10.2 ,足以证明A2线程间发生 B3之前。
因为对给定互斥体的锁定和解锁操作是一次性发生的 订单( [thread.mutex.requirements.mutex]/5 ),我们必须有 A1 或 B2 先来。两种情况:
假设 A1 发生在 B2 之前。然后由 [thread.mutex.class]/1和 [thread.mutex.requirements.mutex]/25 ,我们知道 A4 会与 B2 同步。 因此由 [intro.races]/9.1 , A4 线程间发生在 B2 之前。由于 B2 是 在 B3 之前排序,由 [intro.races]/9.3.1我们知道 A4 线程间 发生在 B3 之前。由于 A2 在 A4 之前排序,因此 [intro.races]/9.3.2 , A2 线程间发生在 B3 之前。
假设 B2 发生在 A1 之前。那么按照上面同样的逻辑,我们知道 B4 与 A1 同步。因此,由于 A1 在 A3 之前排序,因此 [intro.races]/9.3.1 , B4 线程间发生在 A3 之前。因此,由于 B1 是 在 B4 之前排序,由 [intro.races]/9.3.2 , B1 线程间发生在 A3 之前。 因此由 [intro.races]/10.2 , B1 发生在 A3 之前。但后来根据[intro.races]/16 , B1 必须从 pre-A3 状态中取值。因此负载将返回 false,并且 B2 将永远不会运行。也就是说,这种情况不可能发生。
因此,如果 B3 完全执行(案例 1),A2 在 B3 之前发生,并且断言将通过。 ∎
关于C++ 标准 : can relaxed atomic stores be lifted above a mutex lock?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45475241/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])
我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
我经常迷上ruby的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情
我正在使用ruby标准记录器,我想要每天轮换一次,所以在我的代码中我有:Logger.new("#{$ROOT_PATH}/log/errors.log",'daily')它运行完美,但它创建了两个文件errors.log.20130217和errors.log.20130217.1。如何强制它每天只创建一个文件? 最佳答案 您的代码对于长时间运行的应用程序是正确的。发生的事情是您在给定的一天多次运行代码。第一次运行时,Ruby会创建一个日志文件“errors.log”。当日期改变时,Ruby将文件重命名为“errors.log
有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=
出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t