Unix C
Posted shael
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 程序调试器
以上是关于Unix C的主要内容,如果未能解决你的问题,请参考以下文章