我的问题很简单。当你想告诉编译器变量可以在它使用的范围之外改变时,关键字 volatile 是强制性的,例如嵌入式系统中的内存映射变量或可以响应接收信号而改变的信号处理程序变量。操作系统。[删除了关于线程通信的部分,因为它只会产生混乱,这不是我的问题]。[使用下面的评论重新表述问题以澄清]
我认为 OP 所问的是 volatile 是否会增加变量的全局性质尚未施加的进一步限制(事实上,它是全局的,对编译器施加了某些限制,类似于 volatile 强制要求的限制)。
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
bool m_ok = false;
void* run(void*)
{
usleep(1000000);
m_ok = true;
printf ("Good bye!\n");
return nullptr;
}
int main() {
pthread_t my_thread;
pthread_create(&my_thread, nullptr, &run, nullptr);
while (!m_ok)
continue;
printf("YES!!!\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我用以下命令编译上面的代码时,一切都很好:
$ g++ test.cpp -lpthread -std=c++11
$ clang++ test.cpp -lpthread -std=c++11
Run Code Online (Sandbox Code Playgroud)
但是当我尝试使用优化标志时,我的程序没有完成.我测试了以下所有命令:
$ g++ test.cpp -lpthread -std=c++11 -O1
$ clang++ test.cpp -lpthread -std=c++11 -O1
$ g++ test.cpp -lpthread -std=c++11 -O2
$ clang++ test.cpp -lpthread -std=c++11 -O2
Run Code Online (Sandbox Code Playgroud)
我的g ++和clangs的版本也是:
$ g++ --version …Run Code Online (Sandbox Code Playgroud) 我们都知道像这样打字
union U {float a; int b;};
U u;
std::memset(u, 0, sizeof u);
u.a = 1.0f;
std::cout << u.b;
Run Code Online (Sandbox Code Playgroud)
是C++中未定义的行为.
它是未定义的,因为u.a = 1.0f;赋值.a变为活动字段并.b变为非活动字段,并且从非活动字段读取它是未定义的行为.我们都知道这一点.
union U {float a; int b;};
U u;
std::memset(u, 0, sizeof u);
u.a = 1.0f;
char *ptr = new char[std::max(sizeof (int),sizeof (float))];
std::memcpy(ptr, &u.a, sizeof (float));
std::memcpy(&u.b, ptr, sizeof (int));
std::cout << u.b;
Run Code Online (Sandbox Code Playgroud)
现在它变得很明确,因为允许这种类型的惩罚.此外,如您所见,调用u后内存保持不变memcpy().
volatile关键字.
union U {float a; int b;};
volatile U …Run Code Online (Sandbox Code Playgroud) 在Google V8 Javascript引擎的V8.h中,有一段代码可以检查两个类型在编译阶段是否匹配.我可以理解它的大部分内容,但无法理解它的语法static_cast<T* volatile*>,添加异常的volatile*是什么意思,为什么需要?
#define TYPE_CHECK(T, S) \
while (false) { \
*(static_cast<T* volatile*>(0)) = static_cast<S*>(0); \
}
Run Code Online (Sandbox Code Playgroud)
我注意到下面的这个主题已经讨论了相同的代码,但没有详细讨论我要问的问题. 以下代码如何工作?
我知道我应该使用volatile关键字告诉编译器不要优化内存read\write到变量.我也知道在大多数情况下它应该只用于与非C++内存通信.
但是,我想知道volatile在持有指向某个本地(堆栈)变量的指针时是否必须使用.
例如:
//global or member variable
/* volatile? */bool* p_stop;
void worker()
{
/* volatile? */ bool stop = false;
p_stop = &stop;
while(!stop)
{
//Do some work
//No usage of "stop" or p_stop" here
}
}
void stop_worker()
{
*p_stop = true;
}
Run Code Online (Sandbox Code Playgroud)
它看起来像一个编译器,有一些优化级别可能会看到这stop是一个局部变量,它永远不会改变,可以替换while(!stop)为a while(true),从而改变*p_stop而什么都不做.
那么,在这种情况下是否需要将指针标记为易失性?
PS:请不要告诉我为什么不使用它,使用这个hack的真正代码是为了(复杂到解释)的原因.
编辑:
我没有提到这两个函数在不同的线程上运行.它worker()是第一个线程的函数,应该使用p_stop指针从另一个线程停止.
我不知道有什么更好的方法来解决这种黑客背后的真正原因.我只是想知道这是否是C++中定义的\未定义的行为(11),如果这是依赖于编译器\ platform\etc的话.到目前为止,我看到@Puppy说每个人都错了,这是错误的,但没有引用表示这个的特定标准.
我知道你们中的一些人被"不要讲我"这一部分所冒犯,但请坚持真正的问题 - 我应该使用volatile与否?或者是这个UB?如果你能提供一个完整的答案,请帮助我(和其他人)学习新的东西.