Unix C

信号处理
    信号处理的三种方式:忽略、捕捉、执行系统默认操作
    signal与sigaction
        signal与实现有关
        signal不改变信号处理函数就无法获取当前的处理函数
    可重入函数
        异步信号安全的函数
        可重入函数会自动实现中断恢复,即捕获EINTR并重启
    不可重入函数的特征
        1. 使用静态数据
        2. 调用动态内存分配
        3. 标准IO函数
    信号处理程序中,调用非可重入函数的结果不可预知


pthread
    pthread_join与pthread_detach
        join是三种同步线程的方式之一(互斥锁、条件变量)
        线程默认的状态是joinable
        如果一个线程结束运行但没有被join,则它的状态类似于进程中的僵尸进程
        pthread_detach可以有线程自己(pthread_self)或者父线程调用
        detach之后,不可以join
    线程清理
        pthread_cleanup_push pthread_cleanup_pop 必须在相同的作用域中配对使用
        注册线程退出时使用的回调函数(可以注册对多个)
        三种情况触发回调
            1. pthread_exit
            2. 收到pthread_exit发来的PTHREAD_CANCELED
            3. pthread_cleanup_pop 时,输入了参数
    pthread_atfork
        prepare    由父进程在fork创建子进程前调用
        parent    在fork创建了子进程以后,但在fork返回之前在父进程环境中调用
        child    在fork创建了子进程以后,但在fork返回之前在子进程环境中调用


进程同步
    pipe匿名管道
    FIFO命名管道
    socket
    signal
    XSI IPC
        消息队列
        信号量
        共享存储


fork
    进程四个要素:
        1. task_struct
        2. 可执行的代码
        3. 独立的地址空间
        4. 独立的堆栈
    内存复制与COW copy-on-write
        fork之后两个进程共用同一内存,但是地址空间不同
        COW基于页而不基于段
    子进程继承部分
        1. 文件描述符,执行类似dup的操作(包括重定向、文件偏移量)
        2. 信号屏蔽和处理方式
        3. 当前的工作目录
        4. 各种id
        5. 互斥量、读写锁、条件变量的状态(没有exec情况下,需要清楚锁的状态,参见 pthread_atfork)
    fork与多线程
        线程:调用fork的线程外,其他线程在子进程中“蒸发”了
        锁:锁的实现在用户态,父进程的所有锁都会被复制(子进程可以lock已经在父进程中被lock的锁)
    FD_CLOEXEC
        fork出的子进程执行exec之前就不能读写父进程中已打开的文件
https://blog.csdn.net/yangbodong22011/article/details/78648419


exec函数族
    exec函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样
    常与vfork混合使用


wait函数族
    http://man7.org/linux/man-pages/man2/waitid.2.html


孤儿进程与僵尸进程
    孤儿进程:父进程先结束,init收养子进程,并释放其资源
    僵尸进程:子进程先结束,且父进程未收集其状态(子进程运行时才可能被收养,僵尸进程无法转化为孤儿进程)
    僵尸进程解决方案:
        1. fork两次,将僵尸进程转化为孤儿进程
        2. 忽略SIGCHLD(子进程状态改变时产生此信号)
        3. 注册SIGCHLD的回调,并在回调中wait子进程


system
    父进程fork子进程,并wait子进程退出
    信号处理
        SIGINT和SIGQUIT只应该由子进程处理,父进程设置handler为SIG_IGN
        SIGCHLD阻塞
    返回值
        1. 创建子进程等准备工作,system调用失败--status == -1
        2. 调起shell脚本,调起失败或者shell未正常执行(比如信号中断)--WIFEXITED(status)
        3. shell脚本正常执行结束--WEXITSTATUS(status)
    https://blog.csdn.net/keepingstudying/article/details/9299239


task_struct thread_info 内核栈
    内核栈:内核态中,进程使用内核空间中的栈,而不是原用户空间中的栈
    task_struct:描述进程的内核栈
    thread_info:记录部分进程信息,保存了进程描述符中需要频繁访问和快速访问的字段
    https://blog.csdn.net/tiankong_/article/details/75647488


硬链接、软链接
    硬链接是一个指向i-node的路径,inode信息中有一项叫做”硬链接数”
    软链接是一个文件,文件内容为另一个文件路径


不带缓冲的IO函数
    不带缓冲:进程不提供缓冲功能,但内核还是提供缓冲,如read write只单纯的系统调用,不是函数库的调用
    带缓冲:如双重缓冲


select、poll、epoll
    epoll是Linux所特有,而select则应该是POSIX所规定
    select:
        1. 第一个参数是3个描述符集中,最大的描述符编号加一
        2. select提供了比sleep更精确的定时器
        缺点
            1. 最大描述符数为 FD_SETSIZE
            2. 采用线性遍历,效率较低
            3. 从用户空间拷贝fd_set到内核空间进行监控,返回则返回fd_set至用户空间
    poll:
        1. 本质上和select没有区别
        2. 基于链表来存储,没有最大连接数的限制
        3. struct pollfd { int fd; short events; short revents; }
    epoll:
        epoll_create:在内核态分配监控句柄
        epoll_ctl:往内核的数据结构里塞入新的句柄
        epoll_wait:仅从内核态copy符合条件的句柄到用户态
        优点
            1. 使用了内存映射(mmap)技术,解决系统调用时大量的内存拷贝
            2. 采用基于事件的就绪通知方式(epoll_ctl)
        Level Triggered(缺省的工作方式)
            如果没有把数据一次性全部读写完,会一直通知你
            epoll相当于高速版的poll
        Edge Triggered(高速工作方式)
            对比于水平触发,不会一直通知你
            使用方式
                1. 必须使用非阻塞套接口
                2. 返回EAGAIN时,才wait
    http://man7.org/linux/man-pages/man7/epoll.7.html
    https://blog.csdn.net/xiajun07061225/article/details/9250579
http://www.cnblogs.com/Anker/p/3265058.html
https://www.jianshu.com/p/dfd940e7fca2
https://www.cnblogs.com/creazylinux/p/7364685.html
http://www.cnblogs.com/yuuyuu/p/5103744.html


socket
    domain + type + protocol
    如何设置非阻塞
        fcntl--O_NONBLOCK
        ioctl--FIONBIO
        recv/send--MSG_DONTWAIT
    sockaddr 与 sockaddr_in
        sockaddr 是一种通用的结构体,可以用来保存多种类型的IP地址和端口号
        sockaddr_in 是专门用来保存 IPv4 地址的结构体
    http://c.biancheng.net/cpp/html/3033.html
http://man7.org/linux/man-pages/man2/socket.2.html
https://blog.csdn.net/nphyez/article/details/10268723    


mmap
    https://www.cnblogs.com/huxiao-tee/p/4660352.html#undefined
    简化文件读写的操作,提高性能
    多进程共享文件
    https://www.cnblogs.com/huxiao-tee/p/4660352.html


ptrace
    提供了父进程可以观察和控制其子进程执行的能力,并允许父进程检查和替换子进程的内核镜像(包括寄存器)的值
    所有发送给被跟踪的子进程的信号(除了SIGKILL),都会被转发给父进程,而子进程则会被阻塞,这时子进程的状态就会被系统标注为TASK_TRACED
    父进程收到信号后,就可以对停止下来的子进程进行检查和修改,然后让子进程继续运行
    实现:
        strace 跟踪程所执行的系统调用
        gdb 程序调试器
            
原文地址:https://www.cnblogs.com/shaellancelot/p/9021869.html