我使用2个未同步的线程将全局volatile int从0增加到10000000.正如预期的那样,int有时会以10000001结束。
但是,我还要计算两个线程使用特定于线程的局部变量执行增量操作的次数,并且这个线程大量超调。这是代码:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
volatile int x = 0;
void* incThread(void* x) {
int* y;
y = malloc(sizeof(int));
*y = 0;
printf("tstart\n");
while(*((int*)x) < 10000000) {
*y = *y + 1;
*((int*)x) = *((int*)x) + 1;
if(*y % 1000000 == 0) {
printf(">thread at %i\n", *y));
}
}
printf("tend\n");
pthread_exit(y);
}
int main(int argc, char* argv[]) {
pthread_t thread1;
pthread_t thread2;
volatile int* xp;
xp = &x;
int* ret1;
int* ret2;
printf("\n\n\nTHREAD LAUNCH PROGRAM\n");
printf("-------------------------------------\n");
printf("I'll launch two threads.\n");
printf("Both will try incrementing the global value x to 10000000 before exiting.\n\n");
pthread_create(&thread1, NULL, incThread, (void*)xp);
pthread_create(&thread2, NULL, incThread, (void*)xp);
pthread_join(thread1, (void**) &ret1);
pthread_join(thread2, (void**) &ret2);
printf(" Thread01 exited after %i loops.\n", *ret1);
printf(" Thread02 exited after %i loops.\n", *ret2);
printf(" --------\n");
printf(" => %i total\n", ((*ret1)+(*ret2)));
printf("\n");
printf("x ended up at %i.\n", x);
printf("\n");
return 0;
}
所以,运行它会导致它打印出线程的结果。迭代计数器(int in incThread());例如,Thread01&#39; sy = 5801001和Thread02&#39; sy = 5456675,总预期值超过112%,10000000。同时,x本身最终达到10000000或一个更高,正如预期的那样。
是什么给出的?迭代计数如何才能达到这么高的水平?
操作系统信息以及我认为应该发生的事情: 运行的整个虚拟debian 7.1将其亲和性设置为一个CPU核心。 我希望虚拟操作系统在程序的过程中打开3个线程。然后,当它作为常规执行周期的一部分迭代地从一个进程切换到另一个进程时,它还应该继续切换每个进程线程(在这个例子中的主线程和自定义线程1和2)只要专注于那个特定的过程。
所以,有一个主线程启动t1和t2,然后等待thread1完成,一旦完成它等待thread2完成,然后继续打印结果。但据我所知,这并没有解释y如何偏离x这么多。
答案 0 :(得分:4)
这是因为每次两个线程的迭代都可以递增x次。 例如,
t1:读取x值(x为5)
t2:读取x值(x为5)
t1:增量并存储x(x为6)
t2:增量并存储x(x为6)
因此两个线程都完成了迭代,但x的值只增加了一次。理论上,你的线程的 EACH 最多可以运行10000000次。
答案 1 :(得分:2)
我只想提高@chickenpie的答案。以下情况很容易发生:
t1:读取x值(x为5)
t2:读取x值(x为5)
t2:增量并存储x(x为6)
t2:增量并存储x(x为7)
...说10次
t2:增量并存储x(x为17)
t1:增量并存储x(x为6)
当第一个线程从一个物理核心切换到另一个物理核心或者被中断以执行其他任务时,就会发生这种情况。
答案 2 :(得分:0)
这是典型的race condition。 y = y + 1
不是原子的,由3个操作组成:读取,增量,写入。读取操作后可以进行线程切换,其他线程将读取相同的值,递增和写入。然后其他人将继续执行并对相同的值重复相同的操作。所以增量发生了2次,但结果只有一个增量。