关于Linux多线程传递指向主线程本地自动变量的指针的疑惑。

    在读《深入理解计算机系统》原书第二版时,有如下疑惑:在多线程中,使用一个指针作为传递参数,这个指针指向主线程的一个本地自动变量,那么,即使这个本地自动变量不是共享的,但其他线程还是能改变这个变量。在多线程里,除了这个参数没有引用任何共享变量,即这个线程函数是可重入函数,也是线程安全函数。但是如果可以改变他的话,可能在对它值进行更新的时候被其他线程先更新,那这样不是相互矛盾?

经过验证,在多线程里对值进行更新的确会相互冲突,导致所得的数据不是预期数据。

理解:

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

猜你喜欢

转载自blog.csdn.net/ty1121466568/article/details/79688692