假设我们有以下代码:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void guarantee(bool cond, const char *msg) {
if (!cond) {
fprintf(stderr, "%s", msg);
exit(1);
}
}
bool do_shutdown = false; // Not volatile!
pthread_cond_t shutdown_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t shutdown_cond_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Called in Thread 1. Intended behavior is to block until
trigger_shutdown() is called. */
void wait_for_shutdown_signal() {
int res;
res = pthread_mutex_lock(&shutdown_cond_mutex);
guarantee(res == 0, "Could not lock shutdown cond mutex");
while (!do_shutdown) { // while loop guards against spurious wakeups
res = pthread_cond_wait(&shutdown_cond, &shutdown_cond_mutex);
guarantee(res == 0, "Could not wait for shutdown cond");
}
res = pthread_mutex_unlock(&shutdown_cond_mutex);
guarantee(res == 0, "Could not unlock shutdown cond mutex");
}
/* Called in Thread 2. */
void trigger_shutdown() {
int res;
res = pthread_mutex_lock(&shutdown_cond_mutex);
guarantee(res == 0, "Could not lock shutdown cond mutex");
do_shutdown = true;
res = pthread_cond_signal(&shutdown_cond);
guarantee(res == 0, "Could not signal shutdown cond");
res = pthread_mutex_unlock(&shutdown_cond_mutex);
guarantee(res == 0, "Could not unlock shutdown cond mutex");
}
符合标准的 C/C++ 编译器能否在调用 pthread_cond_wait() 时将 do_shutdown 的值缓存到寄存器中?如果不是,哪些标准/条款保证这一点?
编译器可以假设知道 pthread_cond_wait() 不会修改 do_shutdown。这似乎不太可能,但我知道没有任何标准可以阻止它。
实际上,是否有任何 C/C++ 编译器在调用 pthread_cond_wait() 时将 do_shutdown 的值缓存在寄存器中?
编译器保证哪些函数调用不会缓存 do_shutdown 的值?很明显,如果函数是在外部声明的,并且编译器无法访问其定义,则它不能对其行为做出任何假设,因此无法证明它不会访问 do_shutdown。如果编译器可以内联该函数并证明它不访问 do_shutdown,那么即使在多线程设置中它也可以缓存 do_shutdown 吗?同一编译单元中的非内联函数怎么办?
最佳答案
当然,当前的 C 和 C++ 标准对这个主题只字不提。
据我所知,Posix 仍然避免正式定义并发模型(不过我可能已经过时了,在这种情况下,我的答案仅适用于早期的 Posix 版本)。因此,必须带着一点同情来阅读它所说的内容——它并没有精确地列出这方面的要求,但实现者应该“知道它的意思”并做一些让线程可用的事情。
当标准说互斥体“同步内存访问”时,实现必须假设这意味着在一个线程的锁下所做的更改将在其他线程的锁下可见。换句话说,同步操作必须(尽管还不够)包括一种或另一种内存屏障,内存屏障的必要行为是它必须假设全局变量可以改变。
Threads Cannot be Implemented as a Library涵盖了 pthreads 实际可用所需的一些特定问题,但在撰写本文时(2004 年)Posix 标准中并未明确说明。您的编译器编写者或为您的实现定义内存模型的人是否同意 Boehm 的“可用”含义,即允许程序员“令人信服地推理程序的正确性”,这一点变得非常重要。
请注意,Posix 不保证一致的内存缓存,因此如果您的实现反常地想要在代码的寄存器中缓存 do_something,那么即使您将其标记为 volatile,它可能会在同步操作和读取 do_something 之间选择不弄脏 CPU 的本地缓存。因此,如果写入线程在具有自己的缓存的不同 CPU 上运行,即使那样您也可能看不到变化。
这就是(原因之一)为什么线程不能仅仅作为一个库来实现。这种仅从本地 CPU 缓存中获取 volatile 全局变量的优化在单线程 C 实现中是有效的[*],但会破坏多线程代码。因此,编译器需要“了解”线程,以及它们如何影响其他语言特性(例如 pthreads 之外的示例:在 Windows 上,缓存始终是一致的,Microsoft 阐明了它授予 volatile 在多线程代码中)。基本上,您必须假设,如果您的实现在提供 pthreads 函数方面遇到了麻烦,那么它也会在定义一个可行的内存模型时遇到麻烦,在该模型中锁实际上同步内存访问。
If the compiler can inline the function and prove it does not access do_shutdown, then can it cache do_shutdown even in a multithreaded setting? What about a non-inlined function in the same compilation unit?
对所有这些都是肯定的 - 如果对象是非 volatile 的,并且编译器可以证明该线程没有修改它(通过它的名称或通过别名指针),并且如果没有内存障碍发生,那么它可以重用以前的值。当然,有时会有其他特定于实现的条件阻止它。
[*] 前提是实现知道全局不位于某个“特殊”硬件地址,这要求读取始终通过缓存到主内存,以便查看影响该地址的任何硬件操作的结果。但是要在任何这样的位置放置一个全局变量,或者使用 DMA 或其他方式使其位置特殊,需要特定于实现的魔法。如果没有任何这样的魔法,原则上的实现有时可以知道这一点。
关于c++ - C/C++ 编译器能否通过 pthread 库调用合法地将变量缓存在寄存器中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4476446/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。
我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.
我的模型有defself.empty_building//stuffend我怎样才能对这个现有的进行rspec?,已经尝试过:describe"empty_building"dosubject{Building.new}it{shouldrespond_to:empty_building}endbutgetting:Failure/Error:it{shouldrespond_to:empty_building}expected#torespondto:empty_building 最佳答案 你有一个类方法self.empty_bu
我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.
如何将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.你能做的最好的事情是:
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路