在读《深入理解计算机系统》原书第二版时,有如下疑惑:在多线程中,使用一个指针作为传递参数,这个指针指向主线程的一个本地自动变量,那么,即使这个本地自动变量不是共享的,但其他线程还是能改变这个变量。在多线程里,除了这个参数没有引用任何共享变量,即这个线程函数是可重入函数,也是线程安全函数。但是如果可以改变他的话,可能在对它值进行更新的时候被其他线程先更新,那这样不是相互矛盾?
经过验证,在多线程里对值进行更新的确会相互冲突,导致所得的数据不是预期数据。
理解:
1.要为使用的变量单独做一份拷贝,不同的线程使用不同的拷贝,入口指针指向拷贝的数据,这样就能解决多线程数据冲突。
2.在这个可重版函数来说,对变量的操作是通过指针进行,只占一条指令,故其实被打断也没影响
3.个人认为这不是真正的可重入函数
可重入函数
实验代码:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void *thread(void *vargp);
int main(int argc, char **argv)
{
int Counter = 0;
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread, &Counter);
pthread_create(&tid2, NULL, thread, &Counter);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
if(Counter != 20000)
fprintf(stderr, "BOOM! Counter = %d\n", Counter);
else
fprintf(stdout, "OK! Counter = %d\n", Counter);
exit(0);
}
void *thread(void *vargp)
{
int i, niters = 10000;
for(i = 0; i < niters; ++i)
(*((int *)vargp))++;
return NULL;}
相关汇编代码段:
thread:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -24(%rbp)
movl $10000, -4(%rbp)
movl $0, -8(%rbp)
jmp .L6
.L7:
movq -24(%rbp), %rax
movl (%rax), %eax
leal 1(%rax), %edx
movq -24(%rbp), %rax
movl %edx, (%rax)
addl $1, -8(%rbp)
.L6:
movl -8(%rbp), %eax
cmpl -4(%rbp), %eax
jl .L7
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
不可重入函数:
实验代码:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void *thread(void *vargp);
volatile int Counter = 0;
int main(int argc, char **argv)
{
int niters;
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread, NULL);
pthread_create(&tid2, NULL, thread, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
if(Counter != 2 * niters)
fprintf(stderr, "BOOM! Counter = %d\n", Counter);
else
fprintf(stdout, "OK! Counter = %d\n", Counter);
exit(0);
}
void *thread(void *vargp)
{
int i, niters = 10000;
for(i = 0; i < niters; ++i)
Counter++;
return NULL;}
汇编代码段:
thread:
.LFB3:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq %rdi, -24(%rbp)
movl $10000, -4(%rbp)
movl $0, -8(%rbp)
jmp .L6
.L7:
movl Counter(%rip), %eax
addl $1, %eax
movl %eax, Counter(%rip)
addl $1, -8(%rbp)
.L6:
movl -8(%rbp), %eax
cmpl -4(%rbp), %eax
jl .L7
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc