这是代码
struct val {
int x;
int y;
};
struct memory {
struct val *sharedmem;
};
struct val va;
struct memory mem;
void *myThreadFun(void *vargp)
{
va.x = 1;
va.y = 2;
mem.sharedmem = &va;
sleep(1);
printf("Printing GeeksQuiz from Thread0 x = %d y = %d sharedmem = %d\n", va.x, va.y, mem.sharedmem->x);
return NULL;
}
int main()
{
pthread_t tid;
printf("Before Thread \n");
asm volatile ("" ::: "eax", "esi");
pthread_create(&tid, NULL, myThreadFun, NULL);
asm volatile ("mfence" ::: "memory");
printf("sharedmem = %d\n", mem.sharedmem->x); <----- **Here is the fault**
pthread_join(tid, NULL);
printf("After Thread \n");
exit(0);
}
查看dmesg
时显示40073f
为错误地址,
mov eax,DWORD PTR [rax]
我尝试在破坏的寄存器中添加几个通用寄存器,但仍然没有成功。在gdb
下运行时,代码完全正常。
答案 0 :(得分:1)
要扩展我的评论:
编写单线程应用程序时,您可以确定代码的早期部分(有效地)将始终在代码的后续部分之前执行。
但是当你有多个线程时,事情会变得棘手。你怎么知道那时候会发生什么命令呢?线程会快速启动吗?还是慢慢来?主线程会继续处理吗?或者操作系统会安排其他一些线程继续运行,让“新”线程提前比赛吗?
在编写多线程应用程序时,这两种(或多个)线程之间的“竞争”是为了查看谁首先进入代码中的某个点是一个常见问题,并被称为“竞争条件”。众所周知,这些类型的错误很难追查。
如果您不采取任何措施来确保事件的排序,那么您只是“希望”它们以正确的顺序发生。考虑到线程如何安排的自然变化,将会有一些摆动空间。除非你使用一些OS的同步函数来协调线程。
在这种情况下,我们正在查看的事件是设置mem.sharedmem
变量。这是在myThreadFun
主题中完成的。现在,myThreadFun
线程能够在main
线程尝试访问它之前设置变量吗?嗯,很难说肯定。可能。也许不会。
在调试器下运行这个会改变两个线程的运行速度吗?你打赌它确实如此。怎么样?很难预测。
但是,如果您在之前将代码更改为join
线程,则尝试访问该变量,您可以确定线程已完成其工作且变量已准备好使用。 join
是我所指的同步方法之一。
查看您的代码,或许您认为mfence
或memory
clobbers将为您执行此类同步?对不起,但不,这不是那么容易。
学习如何在多个线程之间安全地同步工作是一个挑战性和挑战性的编程领域。重要,有用,但具有挑战性。
EDIT1:
我应该提出的另一点是lfence
,sfence
和mfence
是非常低级的指令。人们(特别是多线程新手)会发现使用atomic functions(根据需要自动使用适当的汇编程序指令)以及操作系统synchronization objects将会更容易找到他们的生活。
关于原子学的教程和讨论比mfence还多。它也往往更便携。