void task1(void* arg) {
static volatile long res = 1;
for (long i = 0; i < 100000000; ++i) {
res ^= (i + 1) * 3 >> 2;
}
}4个线程同时工作,在30秒内执行task1 193次。但4个过程同时工作,在30秒内执行task1 348次。为什么会有这么大的差别?我在MacOSX10.7.5,英特尔核心i5 (4个逻辑核)上测试了它。想想看,Windows和Linux的区别是一样的。
发布于 2013-05-19 14:17:44
res变量是static,这意味着它由同一进程中的所有线程共享。这意味着在四个线程的情况下,一个线程中的res变量的每一个修改都必须对其他线程可用,这通常涉及总线上的某种锁定、一级缓存的失效以及所有其他cpus中的重新加载。
在四个进程的情况下,变量实际上不是由不同的进程共享的,因此它们可以真正并行地运行,而不会相互干扰。
注意,主要的区别不是线程/进程,而是这样一个事实:在一种情况下,每个人都访问相同的变量,而在另一种情况下,每个人访问不同的变量。此外,对于线程,真正的问题不是性能,而是最终结果可能是不正确的事实:
res ^= x;这不是原子操作,处理器将加载res的旧值,然后在寄存器中修改它并将其写回。如果没有同步原语,多个线程可以加载相同的值,独立地修改它,并将其写回变量,在这种情况下,一些线程的工作将被其他线程覆盖。最终结果将取决于不同线程的执行模式,而不是程序的代码。
要模拟变量的不共享,您需要确保线程中访问不同的缓存行。最简单的更改是从变量中删除static限定符,这样每个线程都将更新它自己的堆栈中的变量,与其他线程的变量位于不同的内存地址,并希望映射到不同的缓存行。另一个选项是将四个变量放在一起创建,但在它们之间添加足够的填充,以便将它们扩展到不同的缓存行:
struct padded_long {
volatile unsigned long res;
char [CACHE_LINE_SIZE - sizeof(long)]; // Find this in your processor documentation
};
void f(void *) {
static padded_long res[4];
// detect which thread is running based on the argument and use res[0]..res[3]
// for the different threads发布于 2013-05-19 14:18:39
这是一个进程中所有线程的一个变量:
static volatile long res = 1;因此,如果您只在四个进程中的每个进程中运行一个线程,那么您就有四个不同的"res“存在于不同的内存中。在线程处理的情况下,"res“对于所有四个线程都是相同的变量,因此每次更新时,其他三个处理器都必须使其副本失效(摆脱),并从上次更新它的处理器中获取一个新的。一切都变慢了。如果您实际上想要更新每个线程的变量,我建议您这样做:
void task1(void* arg) {
volatile long* res = const_cast<volatile long *>(
reinterpret_cast<long *>(arg));
for (long i = 0; i < 100000000; ++i) {
res ^= (i + 1) * 3 >> 2;
}
}并从内存的不同部分传入不同的long (例如,使用new long生成每个线程的唯一地址)。
https://stackoverflow.com/questions/16635535
复制相似问题