能帮忙看下这段代码为什么会出现这种结果吗? 关于线程的
代码很简单,启动两个线程,一个对全局变量all加1(用for循环操作360次),另一个减1
但是运行结果却很奇怪,好像每个线程会拥有一个all的拷贝一样,对all操作是对这个拷贝操作,而不是对全局变量操作
- C/C++ code
#include <stdio.h>#include <string.h>#include <windows.h>#define NOPV 1int demo(int argc, char *argv[]);volatile int all = 0;long allsingal = 1;int p(long &singal){ #ifdef NOPV return 1; #endif printf("p\n"); while(singal <= 0) { Sleep(1); } singal--; return 0;}int v(long &singal){ #ifdef NOPV return 1; #endif printf("v\n"); singal++; return 0;}DWORD __stdcall threadadd(LPVOID pfin){ int *finshed = (int *)pfin; int tmp; for (int i = 0; i < 360; i++) { // p(allsingal); tmp = ::all; printf("add all = %d\n", all); Sleep(10); ::all = tmp + 1;// v(allsingal); } *finshed = 1; return 0;}DWORD __stdcall threaddec(LPVOID pfin){ int *finshed = (int *)pfin; int tmp; for (int i = 0; i < 360; i++) {// p(allsingal); tmp = ::all; printf("dec all = %d\n", all); Sleep(10); ::all = tmp - 1;// v(allsingal); } *finshed = 1; return 0;}int main(int argc, char *argv[]){ printf("%d\n" ,argc); DWORD nID1; DWORD nID2; int EndT1 = 0; int EndT2 = 0; CreateThread(NULL, 0, threadadd, &EndT1, 0, &nID1); CreateThread(NULL, 0, threaddec, &EndT2, 0, &nID2); while(!(EndT1 & EndT2)) { printf("all = %d\n", all); Sleep(10); } printf("all = %d\n", all); return 0;}部分结果如下:
all = -260
add all = 261
dec all = -261
all = -261
add all = 262
dec all = -262
all = -262
add all = 263
dec all = -263
all = -263
add all = 264
dec all = -264
all = -264
add all = 265
dec all = -265
all = -265
add all = 266
dec all = -266
all = -266
add all = 267
dec all = -267
all = -267
add all = 268
dec all = -268
all = -268
add all = 269
dec all = -269
all = -269
add all = 270
dec all = -270
all = -270
add all = 271
dec all = -271
all = -271
add all = 272
dec all = -272
all = -272
add all = 273
dec all = -273
all = -273
add all = 274
看得出,线程1总是对一个正的拷贝进行操作
而线程2总是对一个负的拷贝进行操作
[解决办法]
不用volatile修饰得变量,在载入寄存器以后,优化算法是不再去重新载入他,因此看起来会象私有拷贝。
[解决办法]
问题就在 Sleep 的次序上。Sleep会挂起当前的线程,并执行下一个等候的线程。
由于两个线程都有一个 temp 保存 all 的值,这样,大体上的执行过程是这样的:
threadadd:
add.temp = all;
output;
sleep;
threaddec:
dec.temp = all;
output;
sleep;
threadadd:
all = add.temp + 1;
next loop:
add.temp = all;
output;
sleep;
threaddec:
all = dec.temp - 1;
next loop:
dec.temp = all;
output;
sleep;
threadadd:
......
如此循环。
可以看出,输出的值实际上依赖于 temp,而不是 all。
你可以试着把Sleep放到循环的最后,效果应该和放到循环的最前面是一样的。