[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\n", 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----

Unix高级环境编程的更多相关文章

  1. UNIX高级环境编程1

    UNIX高级环境编程1 故宫角楼是很多摄影爱好者常去的地方,夕阳余辉下的故宫角楼平静而安详. 首先,了解一下进程的基本概念,进程在内存中布局和内容. 此外,还需要知道运行时是如何为动态数据结构(如链表 ...

  2. UNIX高级环境编程(14)文件IO - O_DIRECT和O_SYNC详解 < 海棠花溪 >

    春天来了,除了工作学习,大家也要注意锻炼身体,多出去运动运动.  上周末在元大都遗址公园海棠花溪拍的海棠花.   进入正题. O_DIRECT和O_SYNC是系统调用open的flag参数.通过指定o ...

  3. UNIX高级环境编程(16)文件系统 < 雨后 >

    来点绿色放松一下眼睛吧 :) 文件系统是对文件和目录的组织集合. 一 设备文件 设备文件和系统的某个设备相对应. 设备驱动程序 处理设备的所有IO请求. 提供了一致的API接口,对应于系统调用的ope ...

  4. UNIX高级环境编程(15)进程和内存分配 < 故宫角楼 >

    故宫角楼是很多摄影爱好者常去的地方,夕阳余辉下的故宫角楼平静而安详.   首先,了解一下进程的基本概念,进程在内存中布局和内容. 此外,还需要知道运行时是如何为动态数据结构(如链表和二叉树)分配额外内 ...

  5. UNIX高级环境编程(12)进程关联(Process Relationships)- 终端登录过程 ,进程组,Session

    在前面的章节我们了解到,进程之间是有关联的: 每个进程都有一个父进程: 子进程退出时,父进程可以感知并且获取子进程的退出状态. 本章我们将了解: 进程组的更多细节: sessions的内容: logi ...

  6. UNIX高级环境编程(10)进程控制(Process Control)- 竞态条件,exec函数,解释器文件和system函数

    本篇主要介绍一下几个内容: 竞态条件(race condition) exec系函数 解释器文件    1 竞态条件(Race Condition) 竞态条件:当多个进程共同操作一个数据,并且结果依赖 ...

  7. UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

    本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID   1 进程标识符(Process Identifie ...

  8. UNIX高级环境编程(8)进程环境(Process Environment)- 进程的启动和退出、内存布局、环境变量列表

    在学习进程控制相关知识之前,我们需要了解一个单进程的运行环境. 本章我们将了解一下的内容: 程序运行时,main函数是如何被调用的: 命令行参数是如何被传入到程序中的: 一个典型的内存布局是怎样的: ...

  9. UNIX高级环境编程(4)Files And Directories - umask、chmod、文件系统组织结构和链接

    本篇主要介绍文件和文件系统中常用的一些函数,文件系统的组织结构和硬链接.符号链接. 通过对这些知识的了解,可以对Linux文件系统有更为全面的了解.   1 umask函数 之前我们已经了解了每个文件 ...

随机推荐

  1. Testing Is the Engineering Rigor of Software Development

    Testing Is the Engineering Rigor of Software Development Neal Ford DEVELOPERS LOVE TO USE TORTURED M ...

  2. iOS开发UI篇—懒载入

    iOS开发UI篇-懒载入 1.懒载入基本 懒载入--也称为延迟载入,即在须要的时候才载入(效率低,占用内存小).所谓懒载入,写的是其get方法. 注意:假设是懒载入的话则一定要注意先推断是否已经有了. ...

  3. Oracle数据库有用函数

    有用函数 DECODE 语法例如以下: DECODE(value, if1, then1, if2,then2,if3,then3, . . . else )  Value 代表某个表的不论什么类型的 ...

  4. Odoo超售订单

    当 交付给客户的货物多于订购的数量时,就形成'超售'状态: 对于超售的部分,需要进行开票处理,以及根据情况修改交货     发生超售的前提是,产品开票策略为 '按订购数量开票'     同时需要 允许 ...

  5. adb命令具体解释(二)——手机缺失sqlite3时操作数据库的多种解决方式

    在android应用开发无处不在SQLite数据库的身影.那么在开发中怎么使用adb命令操作数据库的功能呢? 以下我们将完整的介绍与数据库操作相关的命令集及当手机缺少sqlite3的时候的多种解决方式 ...

  6. JavaScript插件编写指南

    在编写插件之前,大家要先了解做插件的几个要点: 插件需要满足的条件 一个可复用的插件需要满足以下条件: 插件自身的作用域与用户当前的作用域相互独立,也就是插件内部的私有变量不能影响使用者的环境变量: ...

  7. LINUXFOUNDATION EVENTS

    http://events.linuxfoundation.org/ #lflks This invitation-only event focuses on development and inno ...

  8. HDU 2102 A计划 (BFS)

    A计划 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  9. POJ 3335 Rotating Scoreboard(半平面交 多边形是否有核 模板)

    题目链接:http://poj.org/problem? id=3335 Description This year, ACM/ICPC World finals will be held in a ...

  10. oracle ORA-06550

    declare  cnt integer; begin     select count(0)     into cnt     from user_all_tables    where table ...