首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >易失性变量而不是互斥保护变量来检查更改的数据

易失性变量而不是互斥保护变量来检查更改的数据
EN

Stack Overflow用户
提问于 2014-08-29 18:03:24
回答 4查看 211关注 0票数 0

我有一个线程,它基本上做到了:

代码语言:javascript
复制
int changed; //global variable
..

for (;;) {
   pthread_mutex_lock(&mtx);
   if (changed) {
       do_changes();
       changed = 0;
   }
   pthread_mutex_unlock(&mtx);

   do_stuff();

}

循环每秒运行几十万次,而全局changed变量很少(一天几次)由另一个线程设置。

通过更改为

代码语言:javascript
复制
volatile int changed; //global variable
..

for (;;) {

   if (changed) {
       pthread_mutex_lock(&mtx);
       do_changes();
       changed = 0;
       pthread_mutex_unlock(&mtx);
   }
   do_stuff();
}

使用这种方法,我可以测量到循环的性能提高了3-4%,这是值得追求的。

然而,不鼓励使用易失性变量。这里的方法有什么缺点吗?有没有可能导致2.版本不能按预期工作的情况?

EN

回答 4

Stack Overflow用户

发布于 2014-08-29 18:17:02

volatile不会使您的变量线程安全或原子。为此,您可能会喜欢使用C11 atomics

基本上,您有两个线程更改changed变量,从而覆盖先前的值,从而导致数据争用。

我再怎么推荐你看atomic Weapons: The C++ Memory Model and Modern Hardware也不为过。(它也适用于C语言)。

票数 2
EN

Stack Overflow用户

发布于 2014-08-29 18:53:12

作者:但是,似乎非常不鼓励使用易失性变量。这里的方法有什么缺点吗?有没有可能导致2.版本不能正常工作的情况?

首先:每当你想要使用volatile .时,请三思,如果你现在不需要,看看会发生什么:

1)如果循环在多个线程中,这是不安全的。你可以考虑复制支票:

代码语言:javascript
复制
if (changed) { // quick check
   pthread_mutex_lock(&mtx);
   if (changed) { // another thread could do the work
       ...

2)如果您的代码对查看更改很关键,则需要使用原子,因为pthread_mutex_lock之前的if(changed)可能因为缓存而看不到它。

3)它可以在具有强内存排序和原子int访问的x86(_64)上工作,但在其他体系结构上失败。这就是为什么不鼓励使用volatile的原因,使用原子(并习惯于使用它)。volatile 不强制原子使用或任何其他同步。原子做(读-修改-写指令)。

代码语言:javascript
复制
std::atomic_flag validated;
std::mutex mx; struct MyData { ... } data;
void change() {
    lock_guard<mutex> lock(mx);
    data.something();
    validated.clear();
}
void validate() {
    if(!validated.test_and_set()) {
        lock_guard<mutex> lock(mx);
        data.update();
    }
}

注意::除非您持有锁并为其使用另一个变量,否则您永远无法确定数据是否有效。

4)只需使用pthread_spinlock_t试用您的原始代码

5)小建议:除非你真的知道你在做什么,否则不要扮演同步的上帝。您可以从mutex切换到spinlock (由其他人编写)并进行一些基准测试。

关于编辑和评论的:最初的答案是从1)什么都没有开始。事实证明,有些人既没有阅读完整的问题,也没有阅读完整的答案。皮蒂,那些快速倒下的选民。这个网站不是facebook,这些投票应该是是有帮助的或是没有帮助的,这些向上/向下的投票在facebook上没有喜欢和不喜欢!我可能不同意其他答案的某些部分,但仍然认为它们是有帮助的,虽然不完整(没有回答完整的问题,但只是其中的一部分)或部分不一致(如果我们知道可以没有问题地将相同的值从多个线程写入变量,则没有什么不好的)。

票数 1
EN

Stack Overflow用户

发布于 2014-08-29 19:03:39

如果您使用的是支持它们的C11环境,则可以使用atomic variables。如果你的系统支持它,他们使用特殊的指令来实现原子性,而不是锁。如果你的系统不支持这一点,他们使用锁(标志类型总是无锁的)。

如果您没有C11,但是有一个与GCC兼容的编译器,请参阅sync函数族。它与C11原子变量类似(但更老),但是如果您的系统不支持它们,它们会生成一个函数调用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25566016

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档