我有一个基本上做的话:
int changed; //global variable
..
for (;;) {
pthread_mutex_lock(&mtx);
if (changed) {
do_changes();
changed = 0;
}
pthread_mutex_unlock(&mtx);
do_stuff();
}
循环每秒运行几十万次,而全局changed
变量将被另一个线程很少设置(每天几次)。
更改为
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.版本无法正常工作的极端情况?
答案 0 :(得分:2)
volatile
不会使您的变量线程安全或原子化。您可能希望使用C11 atomics。
你基本上有两个线程改变changed
变量,从而覆盖导致数据竞争的先前值。
我无法建议观看atomic Weapons: The C++ Memory Model and Modern Hardware。 (它也适用于C语言。)
答案 1 :(得分:1)
作者:然而,似乎非常不鼓励变量变量。这种方法有什么缺点吗?任何可能导致2.版本无法正常工作的极端情况?
首先:如果您不需要atomics,那么每当您想要使用volatile
时再想一想。现在看看会发生什么:
1)如果你有多个线程的循环是不安全的。您可以认为有关复制支票的信息:
if (changed) { // quick check
pthread_mutex_lock(&mtx);
if (changed) { // another thread could do the work
...
2)如果您的代码对于看到它已被更改至关重要,则需要使用原子,因为if(changed)
之前的pthread_mutex_lock
可能因缓存而无法看到它。
3)它可以在x86(_64)上使用 强内存排序和原子int访问 ,但在其他架构上失败。这就是为什么不鼓励使用volatile
,使用原子(并使其成为习惯)的原因。 volatile
不强制原子使用或任何其他同步。 Atomics做(读 - 修改 - 写指令)。
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)小建议:除非你真的知道,你在做什么,否则不要与上帝同步。您可以从互斥锁切换到螺旋锁(由其他人编写)并进行一些基准测试。
关于修改和评论:原始答案刚开始时1)之前没有任何内容。事实证明,有些人既没有阅读完整的问题也没有完整的答案。皮蒂那些快速下来的人。这个网站不是Facebook,而且这些投票应该是有用或没有帮助,这些上/下投票不像喜欢和不喜欢的Facebook!我可能不同意其他答案的某些部分,但仍然认为 有帮助,虽然不完整(不是完整的问题,只是其中的一部分)或部分incorrent(如果我们知道我们可以在没有问题的情况下做到这一点,那么从多个线程向变量写入相同的值没有什么不好的。)
答案 2 :(得分:1)
如果您使用支持它们的C11环境,则可以使用atomic variables。如果您的系统支持它,它们使用特殊指令来实现原子性,而不是锁。如果你的系统不支持,他们使用锁(标志类型总是无锁)。
如果您没有C11,但是您有一个兼容GCC的编译器,请参阅sync系列函数。它与C11原子变量类似(但更旧)但如果你的系统不支持它们,它们会产生一个函数调用。
答案 3 :(得分:-1)
最好让它变得易变,以确保编译器不会进行不需要的优化,但它不会使其成为原子。
如果有更多线程读取“已更改”,则当另一个线程等待执行do_changes()时,可能会发生一个线程更新“已更改”为0,这将在因为条件已经评估后释放互斥锁时发生。
如果要避免这种情况,请将if语句移动到互斥锁保护空间内。
希望这有帮助。
卡尔斯。