zl程序教程

您现在的位置是:首页 >  其他

当前栏目

父子进程变量虚拟内存地址相同但变量值不同

2023-04-18 15:42:33 时间

基础介绍

#include<pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wait.h>

//global var
int g_v = 30;

int main(){
    int a_v=30;//local var
    static int s_v = 30;//static var

    int pid = fork();
    if(pid < 0){
        printf("error");
    }else if(pid > 0){//parent
        printf("I am parent process pid is %d
",getpid());
        printf("g_v:%d  a_v:%d  s_v:%d
",g_v,a_v,s_v); 
        g_v = 40;
        a_v = 40;
        s_v = 40;
        printf("g_v : %p
a_v : %p
s_v : %p
",&g_v,&a_v,&s_v);
        printf("g_v:%d  a_v:%d  s_v:%d
",g_v,a_v,s_v);
    }else{
        printf("I am son process pid is %d
",getpid());
        printf("g_v:%d  a_v:%d  s_v:%d
",g_v,a_v,s_v);
        g_v = 50;
        a_v = 50;
        s_v = 50;
        printf("g_v : %p
a_v : %p
s_v : %p
",&g_v,&a_v,&s_v);
        printf("g_v:%d  a_v:%d  s_v:%d
",g_v,a_v,s_v); 
    }
    printf("out
");
    printf("g_v:%d  a_v:%d  s_v:%d
",g_v,a_v,s_v);
    return 0;
}

image

此处:
父进程已经将变量修改为40了,而且子进程与父进程的变量内存地址均是一样的,但是子进程打印变量任然为30.
可见:
父进程和子进程的虚拟地址空间是相同的,但是变量值确实不同。

多线程下死锁

背景

《Linux高性能服务器编程》第14章的代码
用于多进程的时候,子进程会对父进程的锁进行复制,此时很容易出现多次加锁导致死锁。代码如下:

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <wait.h>

pthread_mutex_t mutex;

void* another( void* arg )
{
    printf("我是子线程,打算加锁
");
    pthread_mutex_lock( &mutex );
    printf("我是子线程,成功加锁 我的锁%p
",&mutex);
    sleep( 5 );
    printf("我是子线程,打算解锁
");
    pthread_mutex_unlock( &mutex );
    printf("我是子线程,成功解锁 我的锁%p
",&mutex);
}

void prepare()
{
    printf("prepare加锁
");
    pthread_mutex_lock( &mutex );
    printf("prepare解锁
");
}

void infork()
{
    printf("infork加锁
");
    pthread_mutex_unlock( &mutex );
    printf("infork解锁
");
}

int main()
{
    pthread_mutex_init( &mutex, NULL );
    pthread_t id;
    pthread_create( &id, NULL, another, NULL );
    //pthread_atfork( prepare, infork, infork );
    sleep( 1 );
    int pid = fork();
    if( pid < 0 )
    {
        pthread_join( id, NULL );
        pthread_mutex_destroy( &mutex );
        return 1;
    }
    else if( pid == 0 )
    {
        printf("我是子进程,打算加锁 我的锁%p
",&mutex);
        pthread_mutex_lock( &mutex );
        printf("我是子进程,成功加锁
");
        printf( "I can not run to here, oop...
" );
        printf("我是子进程,打算解锁
");
        pthread_mutex_unlock( &mutex );
        printf("我是子进程,成功解锁
");
        exit( 0 );
    }
    else
    {
        printf( "我是父进程,打算解锁
");
        pthread_mutex_unlock( &mutex );
        printf( "我是父进程,成功解锁 我的锁%p
",&mutex);
        wait( NULL );
    }
    pthread_join( id, NULL );
    pthread_mutex_destroy( &mutex );
    return 0;
}

image

此处明明父进程已经加锁并且解锁后子进程才重新加锁,为什么会被阻塞?就是因为子进程和父进程的变量实质上是不一样的。

解决办法:

  1. 手动在fork前解锁mutex
pthread_mutex_unlock(&mutex);
int pid = fork();
  1. 使用pthread_atfork;
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));