zoukankan      html  css  js  c++  java
  • Unix高级环境编程

    [07] Unix进程环境
    ==================================
    1、 进程终止
        atexit()函数注册终止处理程序。
        exit()或return语句:
            终止处理程序->终止处理程序->标准I/O清除->_exit()->进入内核。
        _exit()直接进入内核。

    2、 环境表
        extern char **environ;
        例:
        for( i=0; environ[i] != NULL; i++)
        {
            printf( "env[%d]: %s ", i, environ[i] );
        }

    3、 C程序存储空间布局
        * 正文                    即代码段
        * 初始化数据段            如:int maxcount = 99;
        * bss(非初始化数据)        如:long sun[1000];
        * 栈                    自动变量及函数调用所需的信息
        * 堆                    动态存取分配,在bss顶端,栈的底端。
        -----------------------------------------------------------
        高地址     栈 -> .... <- 堆  bss  初始数据  正文    低地址
        -----------------------------------------------------------
        注: 可用size命令查看text data bss信息。

    4、 存储器分配
        alloca()是在栈中分配空间,函数调用结束后空间自动释放,但有些系统不支持。

    5、 环境变量
        char * getenv(char * name);
        int putenv( const char * str );
        int setenv(const char * name, const char * value, int rewrite );
        void unsetenv(const char *name );
        注:environ表及字串存放在栈的顶部,当调用上述函数时,可能需将其移到至堆中。

    6、 setjmp和longjmp

        #include <setjmp.h>
            jmp_buf jmpbuffer;
            ......
        _@:    setjmp( jmpbuffer);
            ......
        call    my_function();
            ......
            my_function(){
                longjmp(jmpbuffer, 1 );
            }
        注:
        *    代码中,在_@处调用setjmp函数,然后经过多层调用至my_function函数,
        在该函数中调用longjmp(,1)函数,责程序调整至_@处。
        即:反绕过上层的所有栈帧,跳至_@所在处的栈状态。
        *    setjmp返回值: 如果直接调用,则返回0, 否则返回longjmp的第二个参数。

    7、 getrlimit和setrlimit
        #include <sys/time.h>
        #include <sys/resource.h>
        int getrlimit( int resource, struct rlimit * rlptr );
        int setrlimit( int resource, const struct rlimit * rlptr );



    [08] 进程控制
    ==================================
    1、    进程标识
        进程ID:
            0    交换进程swapper
            1    init,在自举结束后由内核调用。它不会终止,但是它是普通用户进程,以超级用户权限运行。
            2    页精灵进程,pagedaemon
        函数:
        #include <sys/types.h>
        #include <unistd.h>
        pid_t getpid(void);
        pid_t getppid(void);
        uid_t getuid(void);
        uid_t geteuid(void);
        gid_t getgid(void);
        git_t getegid(void);

    2、    fork函数
        fork() : 创建子进程。
        #include <sys/types.h>
        #include <unistd.h>
        pid_t fork(void);

        * 调用fork后,子进程和父进程继续执行fork之后的代码。
        * fork返回两次,子进程返回0,父进程返回子进程ID。
        * fork之后,无法知道父进程和子进程哪个先执行。
        例:
        int main()
        {
            if( (pdi = fork()) < 0 )
                error();
            else if( pid == 0 ){//子进程
            }
            else{                //父进程
            }
            ……                //父子进程继续执行fork之后的代码
        }
        
        两种fork用法
        * fork之后,父子进程各自执行自己的代码。在网络服务器中常见。
        * 进程执行不同的程序。fork后,子进程调用exec函数。

    3、    vfork
        vfork()创建一个新进程。
        与fork区别:
        * vfork保证子进程先于父进程执行,
        * vfork子进程在父进程的地址空间内执行。

    4、 wait和waitpid函数

    5、 竞态条件
        多个进程企图对共享数据进行处理,但结果取决于进程的运行顺序。

    6、 6个exec函数对比
        --------------------------------------------------------------
        函数    path    name        参数表    argv[]        environ    envp[]
        --------------------------------------------------------------
        execl    *                    *                    *
        execlp            *            *                    *
        execle    *                    *                            *
        execv    *                            *            *
        execvp            *                    *            *
        execve    *                            *                    *
        --------------------------------------------------------------
        p    取filename做参数
        l    取参数表
        v    表示去argv[]数组
        e    表示取envp[]数组    


    [10] 信号
    =================================
    1、 概念
        信号:软件中断,以SIG开头,在<signal.h>中定义。
        三种方式处理信号:
        * 忽略此信号,但SIGKILL和SIGSTOP不能被忽略,因为他向超级用户提供了一种使进程终止或停止的可靠方法。如果忽略某些硬件异常产生的信号,则进程的行为未知。
        * 捕捉信号,要通知内核在某信号发生时,调用一个用户函数。
        * 执行系统默认动作。

    2、 signal函数
        #include <signal.h>
        void (*signal (int signo, void (*func)(int))) (int );
        注:
            * 返回值 void (*signal)(int);
              返回老的信号处理程序指针。
            * 参数
              signo: 信号表示
              void (*func)(int); 新的信号处理程序,
               若为SIG_IGN - 忽略此信号
               若为SIG_DFL - 系统默认操作
        
        用typedef方法定义signal函数:
            typedef void Sigfunc(int);
            Sigfunc *signal( int, Sigfunc *);
        
        当进程调用fork时,子进程继承了父进程的信号处理方式。因为子进程开始时复制了父进程的存储映像,所有信号捕捉函数的地址在子进程中式有意义的。

    3、kill和raise函数
        #include <sys/types.h>
        #include <signal.h>

        int kill( pid_t pid, int signo );
        int raise(int signo );
        * kill 将信号发送给进程或进程组
          pid>0 将信号发送给该进程
          pid==0 将信号发送给进程组ID等于发送进程的进程组ID,而且发生进程有许可权向其发送信号的所有进程。
          pid<0 将信号发送给进程组ID等于pid绝对值,与pid==0类似。

        * raise 进程向自身发送信号

    4、alarm和pause函数
        alarm: 设置一时间段,当超过该时间时,产生SIGALRM信号,默认动作时终止该进程。
        #include <unistd.h>
        unsigned int alarm( unsigned int seconds );
        注:
        * seconds 是秒数。
        * 每个进程只能有一个闹钟时间,如果调用alarm时,以前以为该进程设置过闹钟时间,而且还没有超时,则该闹钟时间的余留值作为本次alarm函数调用的返回值。以前登记的闹钟时间被新值替换。
        
        #include <unistd.h>
        int pause(void)
        注:
        只有执行了一个信号处理程序并从其返回,pause才返回-1, errno设为EINTR。

        (书中有很多alarm例子,说明使用信号所要注意的地方)

    5、 信号集
        用sigset_t类型表示一信号集。
        #include <signal.h>
        int sigemptyset(sigset_t * set );
        int sigfillset(sigset_t *set );
        int sigaddset(sigset_t *set, int signo );
        int sigdelset(sigset_t *set, int signo );
        ----返回值: 成功 0, 错误 -1
        int sigismember( conset sigset_t *set, int signo );
        ----返回值: 真 1, 假 0

    6、 sigprocmask函数
        功能:检测或更改进程的信号屏蔽字。
        #include <signal.h>
        int sigprocmask(int how, const sigset_t *set, sigset_t *oset );
        注:
        * 若oset非空, oset为当前信号屏蔽字
        * 若set非空, how指示如何修改当前信号屏蔽字。
        * how:
        *     SIG_BLOCK    或操作
        *     SIG_UNBLOCK 与
        *     SIG_SETMASK 赋值操作

    7、 sigpending函数
        功能:返回调用进程的被阻塞不能递送和当前未决的信号集。
        #include <signal.h>
        int sigpending(sigset_t *set );

    8、 sigaction函数
        功能,取代了signal函数。
        #include <signal.h>
        int sigaction(int signo, const struct sigaction *act,
                struct sigaction * oact );

        struct sigaction{
            void        (*sa_handler)();
            sigset_t    sa_mask;
            int            sa_flags;
        };
        sa_handler    信号捕捉函数
        sa_mask        调用sa_handler之前需要添加的信号屏蔽字,调用结束后,进程的信号屏蔽字再恢复为原先值。
        sa_flags    信号处理选项。

    9、 sigsetjmp和siglongjmp
        #include <setjmp.h>
        int sigsetjmp( sigjmp_buf env, int savemask );
        void siglongjmp( sigjmp_buf env, int val );
        区别:
        当savemask 为非0时,sigsetjmp在env中保存进程的当前屏蔽字,调用siglongjmp时,siglongjmp从中恢复保存的信号屏蔽字。
        而,setjmp和longjmp并不保证该操作。

    10、sigsuspend函数
        #include<signal.h>
        int sigsuspend(const sigset_t sigmask );

        进程的信号屏蔽字设置为sigmask,在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程也被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且该进程的信号屏蔽字设置为调用sigsuspend之前的值。

    [11] 终端

    [12] 高级I/O    
    ====================================
    1、 非阻塞I/O
        对一个给定的描述符有两种方法对其指定非阻塞I/O
        * 如果是调用open以获取描述符,则可以指定O_NONBLOCK标志
        * 对于已经打开的描述符,调用fcntl打开O_NONBLOCK文件状态标志。

    2、 记录锁
        功能: 一个进程正在读或者修改文件的某个部分时,可以阻止其他进程修改同一文件区。它锁定的只是文件的一个区域,也可是整个文件。
        fcntl记录锁
        #include <sys/types.h>
        #include <unistd.h>
        #include <fcntl.h>

        int fcntl ( int filedes, int cmd, struct flock * flockptr );
        参数:
        * cmd        /* F_GETLK, F_SETLK, F_SETLKW */
            F_GETLK    如果存在一把锁,则把现存的锁的信息写到flockptr指向的结构中。若不存在,则将l_type设置为F_UNLCK,其他域保存不变。
            F_SETLK 设置由flockptr所描述的锁。或者用于清除所描述的记录锁(设置l_type为F_UNLCK)。
            F_SETLKW 这是F_SETLK得阻塞版本。

        * flockptr    以下结构指针
        struct flock {
            short l_type;    /* F_RDLCK, F_WRLCK, F_UNLCK */
            off_t l_start;    /* offset in bytes, ralative to l_whence */
            short l_whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
            off_t l_len;    /* length, in bytes; 0 means lock to EOF */
            pid_t l_pid;    /* returned with F_GETLK */
        };

        [注]
        1、当进程终止,锁全部释放,当描述符被关闭时,该描述符的锁也被释放。
        2、fork后,子进程不继承父进程的记录锁
        3、exec后,新程序可以继续原执行程序的锁

    [13] 精灵进程
    ================================
    1. 编程规则
        - 调用fork,然后父进程调用exit。
          用处: 1.如果该精灵进程有Shell启动,那么父进程终止,是的Shell认为该条命令已经执行完成。
              2.保证了子进程不是一个进程组的首进程,它进程了父进程的进程组ID。
        - 调用setsid创建一个新的会话期。
              1.是进程成为对话期首进程。 2.成为一个新进程组的首进程。 3.没有控制终端。
        - 将工作目录更改为跟目录。
        - 将文件方式创建屏蔽字设置为0。
              1.去除由父进程继承得来的屏蔽字。
        - 关闭不需要的文件描述符。这与具体的精灵进程有关。

    #include <sys/type.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    int daemon_init(void)
    {
        pid_t    pid;
        if( (pid = fork() )<0 )
            return -1;
        else if( pid!=0 )
            exit(0);        //parent goes bye-bye
        setsid();
        chdir("/");
        umask(0);        //clear file mode creation mask
        return 0;
    }


    [14] 进程间通信
    ================================
    1、 管道
        #include <unistd.h>
        int pipe( int filedes[2]);
        filedes[0]为读而打开,filedes[1]为写而打开。filedes[1]的输出是filedes[0]的输入。


    14.6----

  • 相关阅读:
    Openstack API 开发 快速入门
    virtualBox虚拟机到vmware虚拟机转换
    使用Blogilo 发布博客到cnblogs
    Openstack Troubleshooting
    hdoj 1051 Wooden Sticks(上升子序列个数问题)
    sdut 2430 pillars (dp)
    hdoj 1058 Humble Numbers(dp)
    uva 10815 Andy's First Dictionary(快排、字符串)
    sdut 2317 Homogeneous squares
    hdoj 1025 Constructing Roads In JGShining's Kingdom(最长上升子序列+二分)
  • 原文地址:https://www.cnblogs.com/xumaojun/p/8541552.html
Copyright © 2011-2022 走看看