APUE-IPC部分

进程间通信

管道

1
int pipe(int fd[2]);
  • 管道是半双工的,且只能在有公共祖先的两个进程之间使用;
  • fd[0]可读,fd[1]可写;
  • 通常用法是先pipe,然后fork,这样父子进程就可以通信:

    fork后的管道

  • 读一个写端已关闭的管道,在所有数据都读取后,read返回0,表示文件结束;

  • 写一个读端已关闭的管道,会产生SIGPIPE,write返回-1,errno设置为EPIPE;
  • 若多个进程同时写管道,且写字节数超过PIPE_BUF,则数据可能相互交叉;
阅读更多
APUE-高级I/O部分

高级IO

非阻塞IO

对于可能使进程永远阻塞的系统调用,如果不想进程一直阻塞,可以将系统调用设为非阻塞:

  • open时指定O_NONBLOCK标志;
  • fcntl对一个打开的描述符设置O_NONBLOCK标志;

这样,如果系统调用无法满足要求,会立刻返回并设定相应错误标志。

记录锁

记录锁保证不会有多个进程同时修改一个文件的同一区域,设置记录锁的POSIX方法是通过fcntl:

  • cmd为F_GETLK, F_SETLK, F_SETLKW, arg是指向flock结构的指针;
阅读更多
APUE-线程部分

线程

线程特点

  • 可以简化异步代码;
  • 共享进程资源;
  • 自身仍有线程ID,寄存器,栈,调度信息,信号屏蔽字,errno,线程私有数据;
  • 需要同步,一个线程异常会导致整个进程异常;

线程创建

1
2
3
4
5
int pthread_equal(pthread_t tid1, pthread_t tid2);
pthread_t pthread_self(void);

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
  • tid存入thread指向空间;
  • attr定义线程属性:
    • 初始化一个属性对象传入;
    • 通过pthread_attr_setdetachstate()设置detachstate属性可使线程创建时就是detach态;
  • 线程从start_routine地址开始运行,参数为arg。
阅读更多
APUE-信号部分

信号

什么是信号

信号提供的是一种处理异步事件的方法,有很多种信号,很多条件可以产生信号,对于进程来说,信号何时发生是无法预测的,进程只能保证当信号发生时做什么,有下面三种做法:

  1. 忽略信号:SIGKILL和SIGSTOP无法忽略;
  2. 捕捉信号:捕捉信号并调用指定函数,SIGKILL和SIGSTOP无法捕捉;
  3. 执行系统默认动作;

中断的系统调用

当执行一个慢速系统调用——可能使进程永远阻塞的系统调用——阻塞时,若捕捉到信号,则此系统调用被中断,出错返回并设置EINTR,有的系统调用会自动重启,有的不会,请注意。

阅读更多
APUE-进程部分

进程环境

程序的启动

内核执行C程序时,先调用启动例程,然后可执行程序文件将启动例程设置为起始地址,启动例程然后从内核获得命令行参数和环境变量,类似下面这样调用main函数:

1
exit(main(argc, argv));

退出函数

1
2
3
void exit(int status);
void _Exit(int status);
void _exit(int status);

这三个函数的区别:

  • exit()会对标准IO进行清洗,关闭所有IO流,并调用注册在atexit和on_exit里的函数(调用顺序与注册顺序相反,可以重复注册),然后调用_exit()。
  • _exit()直接返回内核,清理内存和进程。
  • _Exit()和_exit()等价,只不过前者是标准IO库里的,后者是系统调用。
阅读更多