Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1464918
  • 博文数量: 842
  • 博客积分: 12411
  • 博客等级: 上将
  • 技术积分: 5772
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-14 14:43
文章分类

全部博文(842)

文章存档

2013年(157)

2012年(685)

分类: LINUX

2012-03-04 17:38:18

进程环境

1.1 main函数

1.内核执行C程序的顺序:

   A.调用一个特殊的启动例程。

   B.可执行程序文件将此启动例程指定为程序的起始地址。

   C.启动例程从内核取得命令行参数和环境变量值。

   D.main函数开始执行。

main函数原型:

int main(int argc, char *argv[])

1.2 进程终止

1.进程终止有8种方式,其中:

    5种正常方式:A.main返回

                 B.调用exit

                 C.调用_exit_Exit

                 D.最后一个线程从其启动例程返回

                 E.最后一个线程调用pthread_exit

    3种异常终止:A.调用abort

                 B.接到一个信号并终止

                 C.最后一个线程对取消请求做出响应

2.有三个函数用于正常终止一个程序:_exit_Exit立即进入内核,exit则先执行一些清理处理。

3.终止状态的两种情况:

   .下面3中情形的终止状态是为定义的:

        A.若调用这些退出函数时不带终止状态。

        B.main执行了一个无返回值的return语句。

        C.main没有声明返回类型为整型。

   .下面的情形的终止状态是0

        main的返回类型是整型,并且main执行到最后一条语句时返回(隐式返回),那么该进程的终止状态是0

   注意:exit(0)等价于return(0)

4. 终止处理程序:

头文件:

int atexit(void (*func)(void));

    返回值:成功返回1,否则返回非零值

一个进程可以登记多达32个终止处理程序函数,将由exit自动调用。使用atexit函数来登记这些函数。exit调用这些函数的顺序与它们登记时候的顺序相反,同一函数如果登记多次,则也会调用多次。

5. 图示:一个c程序是如何启动,以及它可以终止的方法:

 

6. 函数原型:

    void exit(int status);

    void _Exit(int status);

    头文件:stdlib.h

    函数功能:正常终止一个程序。

    void _exit(int status);

    头文件:unistd.h

    函数功能:正常终止一个程序。  

7. 示例:

 ********************  7-2 ********************** 

 //终止处理程序的使用。使用到atexit函数

#include "apue.h"

 

static void my_exit1(void);

static void my_exit2(void);

 

 

int

main(void)

{

    if(atexit(my_exit2) != 0)

    printf("can not register my_exit2\n");

    if(atexit(my_exit1) != 0)

    printf("can not register my_exit1\n");

    if(atexit(my_exit1) != 0)

    printf("can not register my_exit1\n");

    printf("main is done \n");

 

    return 0;

}

static void my_exit1(void)

{

    printf("first exit handler\n");

 

}

 

static void my_exit2(void)

{

    printf("second exit handler\n");

}

结果:

main is done

first exit handler

first exit handler

second exit handler

注意exit调用这些函数的顺序与它们登记时候的顺序相反,同一函数如果登记多次,则也会调用多次。而且主函数是先结束的,当然其实主函数还是应该是在清理函数后结束的,我这么觉得的。

***********************************************

1.3 命令行参数

例程2

#include "apue.h"

 

int

main(int argc, char *argv[])

{

    int i;

    char **ptr;

    extern char **environ;

    for(i = 0;i < argc; i++ )

    printf("argv[%d] : %s \n", i, argv[i]);

    for(ptr = environ; *ptr != 0; ptr++)

    printf("%s\n", *ptr);

 

 

    return 0;

}

 

运行结果:

argv[0] : ./7-3

argv[1] : gong

argv[2] : fun1

argv[3] : fun2

SSH_AGENT_PID=2523

HOSTNAME=localhost.localdomain

TERM=xterm

SHELL=/bin/bash

HISTSIZE=50

GTK_RC_FILES=/etc/gtk/gtkrc:/root/.gtkrc-1.2-gnome2

WINDOWID=20972290

USER=root

LS_COLORS=no=00:fi=00:di=00;34:ln=00;36:pi=40;33:so=00;35:bd=40;33;01:cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=00;32:*.cmd=00;32:*.exe=00;32:*.com=00;32:*.btm=00;32:*.bat=00;32:*.sh=00;32:*.csh=00;32:*.tar=00;31:*.tgz=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.zip=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.bz=00;31:*.tz=00;31:*.rpm=00;31:*.cpio=00;31:*.jpg=00;35:*.gif=00;35:*.bmp=00;35:*.xbm=00;35:*.xpm=00;35:*.png=00;35:*.tif=00;35:

SSH_AUTH_SOCK=/tmp/ssh-XXmoci9Y/agent.2509

SESSION_MANAGER=local/localhost.localdomain:/tmp/.ICE-unix/2509

USERNAME=root

MAIL=/var/spool/mail/root

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin

INPUTRC=/etc/inputrc

PWD=/root/unixfile

XMODIFIERS=@im=Chinput

LANG=zh_CN.GB2312

SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass

SHLVL=3

HOME=/root

LANGUAGE=zh_CN.GB18030:zh_CN.GB2312:zh_CN

GNOME_DESKTOP_SESSION_ID=Default

BASH_ENV=/root/.bashrc

LOGNAME=root

LESSOPEN=|/usr/bin/lesspipe.sh %s

DISPLAY=:0.0

G_BROKEN_FILENAMES=1

COLORTERM=gnome-terminal

XAUTHORITY=/root/.Xauthority

OLDPWD=/root/unixfile/db

_=./7-3

注意命令行参数的使用。

1.4 环境表

1. 环境表是一个字符指针数组,全局变量environ则包含了该指针数组的地址:

    extern char ** environ;

2. 使用getenvputenv函数来访问特定的环境变量。

    使用environ指针来获得整个环境表。

1.5 C程序的存储空间布局

1. C程序的组成:

     A. 正文段。这是由CPU执行的机器指令部分。

     B. 初始化数据段。通常将此段称为数据段。它包含了程序中需明确地赋初值的变量。

     C. 非初始化数据段。通常将此段称为bss段。在程序开始执行之前,内核将此段中的数据初始化为0或空指针。

     D. 栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。

     E. 堆。通常在堆中进行动态存储分配。

2. 图示,典型的存储器安排:

     

1.6 共享库

      共享库使得可执行文件中不再需要包含公用的库例程,而只需在所有进程都可引用的存储区中维护这种库例程的一个副本。程序第一次执行或者第一次调用某个库函数时,用动态链接方法将程序与共享库函数相链接。这减少了每个可执行文件的长度,但增加了一些运行时间开销。

1.7 存储器分配

1. malloc函数:分配指定字节数的存储区。此存储区中的初始值不确定。

    calloc函数:为指定数量和指定长度的对象分配存储空间,该空间每一位都初始化为0.

    realloc函数:更改以前分配区的长度(增加或减少),而新增区域内的初始值则不确定。

    注:使用sbrk系统调用实现。

2. 函数原型:

    void *malloc(size_t size);

    void *calloc(size_t nobj, size_t size);

    void *realloc(void *ptr, size_t newsize);

    void free(void *ptr);

    头文件:stdlib.h

    返回值:前三个函数,若成功则返回非空指针,若出错则返回NULL

1.8 环境变量

1. 函数原型

    char *getenv(const char * name);

    返回值:指向关联namevalue值的指针,若没有找到返回NULL

    int putenv(char *str);

    返回值:成功返回0,否则返回非0

    int setenv(const char * name,const char *value,int rewrite); //rewrite为非0,则改变其值;若为0,其值不变。

返回值:成功返回0,否则返回非0

    int unsetenv(const char *name);

返回值:成功返回0,否则返回非0

    头文件:stdlib.h

    函数功能:获取或设置环境变量

    返回值:getenv返回指向与name关联的value的指针,若未找到则返回NULL。其余函数若成功则返回0,若出错则返回非0

1.9 setjmplongjmp函数

1. 函数原型:

    int setjmp(jmp_buf,env);

    void longjmp(jmp_buf env,int val);

    头文件:

    返回值:setjmp若直接调用则返回0,若从longjmp调用返回则返回非0(其值是longjmp设置的val的值).               

    函数功能:执行非局部跳转。

    使用方法:希望返回到的位置调用setjmp。需要跳转的地方调用longjmp 

2.示例:

   ***************  7-2 ****************************

   //演示使用setjmplongjmp实行非局部跳转

   //假设“i==2&&wrong2==1 ”“i==4&&wrong4==1”时是错误,于是发生跳转

   #include
   #include

   jmp_buf jmpbuffer;
   int wrong2=1;
   int wrong4=1;

   void dochar(int i)
  {
        if(i==2&&wrong2==1)
       {
              wrong2=0;
              longjmp(jmpbuffer,2);
       }
        if(i==4&&wrong4==1)
       {
              wrong4=0;
              longjmp(jmpbuffer,4);
       }
        printf("i=%d\n",i);
  }


  void doline(int i)
  {
         dochar(i);
  }


   int main()
  {
         int setReturn;
         int i=0;
         if((setReturn=setjmp(jmpbuffer))!=0)
        {
               printf("error,return=%d\n",setReturn);
        }
         for(i=0;i<=5;i++)
        {
              doline(i);
        }
         return 0;
   }

  运行结果:

   root@BDAMA:~/study# ./161
   i=0
   i=1
   error,return=2
   i=0
   i=1
   i=2
   i=3
   error,return=4
   i=0
   i=1
   i=2
   i=3
   i=4
   i=5

**************************************************** 

1.10 getrlimitsetrlimit函数

1. rlimit结构体:

    struct rlimit
   {
         rlim_t rlim_cur;      /* The current (soft) limit.  */
         rlim_t rlim_max;    /* The hard limit.  */
   };

2.更改资源限制时,须遵守的3条规则:

   A. 任何一个进程都可将一个软限制值改为小于或等于其硬限制值。

   B. 任何一个进程都可降低其硬限制值,但它必须大于或等于其软限制值。这种限制对普通用户是不可逆的。

   C. 只有超级用户进程可以提高硬限制值。

3. 函数原型

    int getrlimit(int resource,struct rlimit *rlptr);

    int setrlimit(int resource,const struct rlimit *rlptr);

    头文件:

    返回值:若成功返回0,若出错返回非0值。

    函数功能:获取或修改资源的限制值。

4. 资源参数(getrlimit函数和setrlimit函数的resource的值)

    RLIMIT_CPU             //Per-process CPU limit, in seconds.
    RLIMIT_FSIZE           //Largest file that can be created, in bytes.
    RLIMIT_DATA            // Maximum size of data segment, in bytes.
    RLIMIT_STACK          //Maximum size of stack segment, in bytes.
    RLIMIT_CORE           //Largest core file that can be created, in bytes.
    RLIMIT_RSS              //Largest resident set size, in bytes.
    RLIMIT_NOFILE         //Number of open files.
    RLIMIT_AS                //Address space limit.
    RLIMIT_NPROC         //Number of processes.
    RLIMIT_MEMLOCK     //Locked-in-memory address space.
    RLIMIT_LOCKS          //Maximum number of file locks.
    RLIMIT_SIGPENDING //Maximum number of pending signals.  
    RLIMIT_MSGQUEUE   //Maximum bytes in POSIX message queues.
    RLIMIT_NICE             //Maximum nice priority allowed to raise to.
    RLIMIT_RTPRIO         //Maximum realtime priority allowed for non-priviledged processes.
    RLIMIT_NLIMITS

5. 示例:

    **********************  7-3 ***************************

    //获取和修改资源限制的值

    #include
    #include

    int main()
   {
         struct rlimit prl;
         getrlimit(RLIMIT_DATA,&prl);
         printf("rlim_cur=%lu,rlim_max=%lu\n",prl.rlim_cur,prl.rlim_max);
         prl.rlim_cur=100;
         prl.rlim_max=200;
         if(setrlimit(RLIMIT_DATA,&prl)!=0)
         {
               printf("setrlimit wrong!\n");
         }

         getrlimit(RLIMIT_DATA,&prl);
         printf("rlim_cur=%lu,rlim_max=%lu\n",prl.rlim_cur,prl.rlim_max);

         return 0;
    }
   *********************************************************

阅读(1178) | 评论(0) | 转发(2) |
0

上一篇:进程间通信

下一篇:进程同步

给主人留下些什么吧!~~