分页: 1 / 1

对于fork()的疑问

发表于 : 2009-05-12 11:06
lonelycorn
fork()的返回值
-1:失败
0:这是子进程
>0:这是父进程,返回值是子进程的pid

现在我写了一个程序,fork()成两个线程,子进程execv了一个"test"的小程序,父进程去监控子进程的运行情况(内存、信号,等等)具体来说就是cat /proc/<pid>/stat。
但是现在出现了一个问题,fork()后返回给父进程的pid好像有时候是父进程的pid,而不是子进程的pid
比如,我期待的输出是

代码: 全选

pid is 5861,pid_string is 5861
5861 (test) R 5860 5860 4200 34816 5860 4202496 55 0 0 0 18 0 0 0 20 0 1 0 342997 40214528 18 4294967295 134512640 134608672 3218846416 3218846408 134512790 0 0 0 1224 0 0 0 17 1 0 0 0 0 0
40214528.18
vmsize=39272,vmrss=72
5861 (test) R 5860 5860 4200 34816 5860 4202496 55 0 0 0 18 0 0 0 20 0 1 0 342997 40214528 18 4294967295 134512640 134608672 3218846416 3218846408 134512780 256 0 0 1224 0 0 0 17 1 0 0 0 0 0
0.0
vmsize=0,vmrss=0
也就是显示我execv的test的运行情况,但是有1/10的概率出现下面的结果:

代码: 全选

pid is 5868,pid_string is 5868
5868 (tmp) R 5867 5867 4200 34816 5867 4202560 0 0 0 0 0 0 0 0 20 0 1 0 343116 2899968 26 4294967295 134512640 134521899 3217852880 3217852544 3087717424 0 0 0 0 0 0 0 17 0 0 0 0 0 0
2899968.56
vmsize=2832,vmrss=224
5868 (tmp) R 5867 5867 4200 34816 5867 4202560 37 0 0 0 0 0 0 0 20 0 1 0 343116 4096 1 4294967295 0 0 0 3217852576 3087717424 256 0 0 0 0 0 0 17 0 0 0 0 0 0
0.0
vmsize=0,vmrss=0
显示的是父进程(我的程序编译后叫tmp)的状况。

请问这是为什么?是不是我检测到的是还没有执行execv的子进程?
thx in advance

Re: 对于fork()的疑问

发表于 : 2009-05-12 11:15
taylor
看不懂你贴的是什么,code呢

Re: 对于fork()的疑问

发表于 : 2009-05-14 21:49
lonelycorn
上代码了

代码: 全选

#include <iostream>
#include <fstream>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

const double DELTA = 1.0;
const int TIME = 100;
const int MEM = 18192;
const int OFFSET = 10;

using namespace std;

char *pid_to_string(int pid)
{
    char s[50];
    sprintf(s,"%d",pid);
    char *s1=s;
    return s1;
}

int pid_to_string(int pid,char *s)
{
    sprintf(s,"%d",pid);
    return 0;
}


long get_memory(int pages)
{
    long factor = 0;
    factor = (long)sysconf(_SC_PAGESIZE);
    return pages*factor/1024;
}

void get_timespec(struct timespec *s, int time)
{
    s->tv_sec = time / 1000;
    s->tv_nsec = (time % 1000 ) * 1000000;
}

/*
return 0 if OK
return 1 if MLE
*/
int check_memory(char *pid_string)
{
    using std::ios_base;
    using std::ifstream;
    using std::string;

    double vm_usage     = 0.0;
    double resident_set = 0.0;

    // 'file' stat seems to give the most reliable results
    //
    char buffer[100];
    sprintf(buffer,"/proc/%s/statm",pid_string);
    ifstream statm_stream(buffer,ios_base::in);

    long vmsize=0;
    statm_stream>>vmsize;
    vmsize=vmsize*sysconf(_SC_PAGESIZE)/1024;
    cerr<<"vmsize is "<<vmsize<<endl;
    struct rusage used;
    getrusage(RUSAGE_CHILDREN,&used);
    cerr<<"memory usage:"<<used.ru_minflt*sysconf(_SC_PAGESIZE)/1024<<endl;

}

int main()
{
    srand((unsigned) time(NULL));
    pid_t pid=fork();

    if ( pid == -1)
    {
        cerr<<"error while forking"<<endl;
        exit(EXIT_FAILURE);
    }
    else if (pid == 0)
    {
        struct rlimit limit;
        /* time limit */
        limit.rlim_cur=limit.rlim_max=1;
        setrlimit(RLIMIT_CPU,&limit);
        /* memory limit */
         limit.rlim_cur=limit.rlim_max=MEM * 1024;
         setrlimit(RLIMIT_AS,&limit);

        char *argv[]={(char *)"test",(char *)NULL};
        execv(argv[0],argv);
        cerr<<"failed to execv"<<endl;
        exit(5);
    }
    else if (pid > 0)
    {
        int status,tmp,left_t;
        struct timespec spec;
        char pid_string[20];
        pid_to_string(pid,pid_string);

        get_timespec(&spec,OFFSET);
        left_t = TIME;

        while (1)
        {
            tmp = waitpid(pid,&status,WNOHANG);
            if (tmp!=0) break;
            /* check resource usage */
            if ( (rand() % 100) < 100)
            {
                tmp = check_memory(pid_string);
                if (tmp>0)
                {
                    switch (tmp)
                    {
                        case 1 :cerr<<"time limit exceeded"<<endl;break;
                        case 2 :cerr<<"memory limit exceeded"<<endl;break;
                    }
                    kill(pid,SIGKILL);
                    break;
                }
            }
            nanosleep(&spec,NULL);
            left_t -= OFFSET;
            if (left_t<=0)break;
        }
        tmp = check_memory(pid_string);

        struct rusage used;
        getrusage(RUSAGE_CHILDREN,&used);
        printf("ru_maxrss:%ld\n",used.ru_maxrss);
        printf("ru_ixrss:%ld\n",used.ru_ixrss);
        printf("ru_idrss:%ld\n",used.ru_idrss);
        printf("ru_isrss:%ld\n",used.ru_isrss);
        printf("ru_minflt:%ld\n",used.ru_minflt);
        printf("ru_majflt:%ld\n",used.ru_majflt);
        printf("ru_nswap:%ld\n",used.ru_nswap);
        printf("ru_inblock:%ld\n",used.ru_inblock);
        printf("ru_oublock:%ld\n",used.ru_oublock);
        cerr<<"memory usage:"<<used.ru_minflt*sysconf(_SC_PAGESIZE)/1024<<endl;



        tmp = waitpid(pid,&status,WNOHANG);
        if (tmp == 0)
        {
            kill(pid,SIGKILL);
            cerr<<"time limit exceeded,killed"<<endl;
        }

        if (WIFEXITED(status))
        {
            cerr<<"child thread exit normally"<<endl;
            cerr<<"child thread exit status is "<<WEXITSTATUS(status)<<endl;
        }
        else
        {
            cerr<<"child thread exit abnormally"<<endl;
            if (WIFSIGNALED(status))
            {
                switch (WTERMSIG(status))
                {
                    case SIGXCPU:cerr<<"SIGXCPU:time limit exceeded"<<endl; break;
                    case SIGXFSZ:cerr<<"SIGXFSZ:file size exceeded"<<endl;  break;
                    case SIGSEGV:cerr<<"SIGSEGV:segmentation fault"<<endl;  break;
                    default:cerr<<"caught signal "<<WTERMSIG(status)<<endl; break;
                }
            }
            cerr<<"child thread exit status is "<<WEXITSTATUS(status)<<endl;

        }
        exit(EXIT_SUCCESS);
    }

}

Re: 对于fork()的疑问

发表于 : 2009-05-14 21:50
lonelycorn
中间废话多了点,但是大体内容就是fork()后检查/proc/pid/statm

Re: 对于fork()的疑问

发表于 : 2009-05-14 22:35
peachcolor
好长啊,木有耐心

Re: 对于fork()的疑问

发表于 : 2009-05-15 21:29
lonelycorn
OK,Let's精简

代码: 全选

#include <iostream>
#include <fstream>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

const double DELTA = 1.0;
const int TIME = 100;
const int MEM = 18192;
const int OFFSET = 10;

using namespace std;

/*
将时间转换为struct timespec格式
*/
void get_timespec(struct timespec *s, int time)
{
    s->tv_sec = time / 1000;
    s->tv_nsec = (time % 1000 ) * 1000000;
}

/*
return 0 if OK
return 1 if MLE
从/proc/pid/stat读入内存信息
*/
int check_memory(int pid)
{
    using std::ios_base;
    using std::ifstream;
    using std::string;

    double vm_usage     = 0.0;
    double resident_set = 0.0;

    // 'file' stat seems to give the most reliable results
    //
    char buffer[100];
    sprintf(buffer,"/proc/%d/statm",pid);
    ifstream statm_stream(buffer,ios_base::in);

    long vmsize=0;
    statm_stream>>vmsize;
    vmsize=vmsize*sysconf(_SC_PAGESIZE)/1024;
    cerr<<"vmsize is "<<vmsize<<endl;
    struct rusage used;
    getrusage(RUSAGE_CHILDREN,&used);
    cerr<<"memory usage:"<<used.ru_minflt*sysconf(_SC_PAGESIZE)/1024<<endl;

}

int main()
{
    srand((unsigned) time(NULL));
    pid_t pid=fork();

    if (pid == 0)
    {
        /* 子进程,设置一些限制,然后execv() */
        struct rlimit limit;
        /* time limit */
        limit.rlim_cur=limit.rlim_max=1;
        setrlimit(RLIMIT_CPU,&limit);
        /* memory limit */
         limit.rlim_cur=limit.rlim_max=MEM * 1024;
         setrlimit(RLIMIT_AS,&limit);

        char *argv[]={(char *)"test",(char *)NULL};
        execv(argv[0],argv);
    }
    else if (pid > 0)
    {
        /* 父进程,监视子进程的内存*/
        int status,tmp,left_t;
        struct timespec spec;

        get_timespec(&spec,OFFSET);
        left_t = TIME;

        while (1)
        {
            tmp = waitpid(pid,&status,WNOHANG);
            if (tmp!=0) break;
            /* check resource usage */
            tmp = check_memory(pid);
            if (tmp>0)
            {
                switch (tmp)
                {
                    case 1 :cerr<<"time limit exceeded"<<endl;break;
                    case 2 :cerr<<"memory limit exceeded"<<endl;break;
                }
                kill(pid,SIGKILL);
                break;
            }
            nanosleep(&spec,NULL);
            left_t -= OFFSET;
            if (left_t<=0)break;
        }
    }
}