【现象】:linux,c语言程序, -O3优化。线程a对变量x赋值,int x=0
,并将变量x地址传给线程b,线程b对变量x再次执行赋值操作x=2
,此时在线程a内部访问变量x,值仍然为0,并未立刻刷新。
【解决过程】:
① 尝试对x变量类型前加volatile关键字:问题仍然存在,原因是虽然volatile会要求每次读取变量都从主存读取,但由于cpu cache的存在,仍然读取的是cache中的内容,此方法无法彻底解决多线程访问变量及时刷新的问题;
② 将x由普通的int类型变为指针类型int *x
,每次从指针读取一个malloc的int类型变量,问题解决。原因可能是指针的读取操作会进行二次寻址,不会受到cpu cache的影响。
linux c,简单测试代码:
编译命令:
gcc -g -O3 -o main main.c -pthread
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <memory.h>
#include <stdlib.h>
typedef struct test {
int *a; // 即便先启动thread2(避免线程启动时间影响),后启动thread1,用volatile 还是有可能thread1变量没有刷新(一定的概率)
} test_t;
void *thread1(void *param)
{
test_t *p_param = param;
//p_param->a = -2;
usleep(1000);
test_t *p_param2 = (test_t *)(param + sizeof(test_t));
while (1) {
printf("%p\n", p_param2->a);
if (NULL != p_param2->a) {
printf("%d\n", *(p_param2->a));
break;
}
}
return NULL;
}
void *thread2(void *param)
{
usleep(900);
test_t *p_param = param;
test_t *p_param2 = (test_t *)(param + sizeof(test_t));
int *p = (int *)malloc(sizeof(int));
*p = 3;
p_param2->a = p;
printf("after %d\n", *(p_param2->a));
return NULL;
}
int main()
{
pthread_t t[2];
int r[2];
test_t *a = (test_t *)malloc(2 * sizeof(test_t));
memset(a, 0x00, 2 * sizeof(test_t));
r[1] = pthread_create(&t[1], NULL, thread2, (void *)a);
r[0] = pthread_create(&t[0], NULL, thread1, (void *)a);
pthread_join(t[0], NULL);
pthread_join(t[1], NULL);
return 0;
}