[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. openssl之EVP系列之11---EVP_Verify系列函数介绍

    openssl之EVP系列之11---EVP_Verify系列函数介绍     ---依据openssl doc/crypto/EVP_VerifyInit.pod翻译和自己的理解写成     (作者 ...

  2. Linux mm相关的问题

    [S]为什么High MEM是从896M開始的? As the running kernel needs these functions, a region of at least VMALLOC_R ...

  3. Libx264 编码错误 Input picture width(320) is greater than stride (0)

    Ffmpeg libx264编码出现 Input picture width(320) is greater than stride (0),问题出在视频格式不正确. libx264 编码要求输入源的 ...

  4. Java面向对象基础三

    1.函数的重载 2.构造函数的作用 (构造函数能够重载) 1.函数名必须和类名同样 2.没有返回值 3.使用 New 来调用构造函数 4.假设类中没有构造函数,编译器会自己主动帮忙载入一个參数为空.方 ...

  5. ZeroClipboard—ZeroClipboard的使用

    1.ZeroClipboard的作用: 借助Zero Clipboard能够简单高速地将内容拷贝到剪贴板,相似点击某些网页中"复制"按钮后复制对应区域的内容. 2.ZeroClip ...

  6. LookAround开元之旅

    http://blog.csdn.net/lancees/article/details/17696805

  7. 图像滤镜艺术---PS图层混合模式之明度模式

    本文将介绍PS图层混合模式中比較复杂 的"明度"模式的算法原理及代码实现内容. 说到PS的图层混合模式,计算公式都有,详细代码实现也能找到,可是,都没有完整介绍全部图层混合模式的代 ...

  8. NoSQL的四大类型

    1 键值数据库 相关产品:Redis.Riak.SimpleDB.Chordless.Scalaris.Memcached 应用:内容缓存 优点:扩展性好.灵活性好.大量写操作时性能高 缺点:无法存储 ...

  9. [工具]利用EasyRTSPClient工具检查摄像机RTSP流不能播放原因以及排查音视频数据无法播放问题

    出现问题 我们在做流媒体开发的过程中,进程会出现摄像机RTSP流莫名其妙无法播放的问题,而我们常用的vlc经常是直接弹出一个无法播放的提示框就完事了,没有说明出错的原因,或者在vlc的消息里面能看到日 ...

  10. Struts2中的OGNL表达式

    一.OGNL表达式简介 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目.所谓对象图,即以任意一个对象为根,通过OGNL可以访问 ...