APUE学习笔记(部分)
第一章 Unix基础知识
操作系统的体系结构
输入输出
头文件<unistd.h>
- 每当运行一个新程序时,所有的shell 都为其打开3 个文件描述符,即标准输入(standard input )、标准输出( standard output ) 以及标准错误(standard error )
- open read write lseek close提供了不带缓冲的IO
- 两个常量STDIN_FILENO和STDOUT_FILENO指定了标准输入输出的文件描述符。STDERR_FILENO定义了标准错误的描述符
系统调用与库函数
- C库函数与系统调用的差别
- 系统调用通常提供一种最小接口 , 而库函数通常提供比较复杂的功能 。
第二章 Unix标准及实现
标准及限制略
选项
头文件<unistd.h>
- 与文件或目录无关的运行时选项用 sysconf 函数来判断
- 文件或目录有关的运行时选项通过调用pathconf 或 fpathconf 函数来判断
基本数据类型
头文件<sys/type.h>
- 一些常用的基本数据类型
第三章 文件IO
对于内核而言,所有打开的文件都通过文件描述符引用,当打开或创建一个文件是,内核都向进程返回一个文件描述符。标准输入输出描述符如:
open与opennat
头文件<fcntl.h>
- 打开或创建一个文件
- oflag参数(读写):
下列参数必须且只可指定一个
O_RDONLY 只读打开
O_WRONLY 只写打开
O_RDWR 读、写打开
O_EXEC 只执行打开
O_SEARCH 只搜索打开 - oflag参数(可选)
O_APPEND 每次写追加到文件的尾端
O_CLOEXEC 把FD_CLOEXEC常量值设置为文件描述符标志
O_CREAT 文件不存在则创建它,新创建的文件访问权限位由mode参数指定
O_EXCL 若文件已存在,则出错
O_NOCTTY 不讲path引用的终端设备作为进程的控制终端
O_DIRECTORY path不是目录则出错
O_NOFOLLOW NO符号链接
O_NOBLOCK 非阻塞方式
O_TRUNC 文件存在则文件长度截断为0
文件操作函数
头文件<unistd.h>
- int creat (const char *path, mode_t mode);
等效于
int open (const char *path, O_WRONLY|O_CREAT_O_TRUNC, mode_t mode); - int close (int fd)
- off_t lseek (int fd, off_t offset, int whence);
whence:
SEEK_SET 开始处设置
SEEK_CUR 当前位置设置
SEEK_END 文件结束位置设置 - write read
fd, *buf, size
返回操作的字数
文件共享
函数dup和dup2
头文件<unistd.h>
- 函数返回的新文件描述符与参数fd共享同一个文件表项。
函数fcntl
头文件<fcntl.h>
- 形式:
int fcntl ( int fd, int cmd, … /* int arg */ ); - 功能:
函数 ioctl
头文件<unistd.h>
<sys/ioctl.h>
- 形式:
int ioctl (int fd, int request, … );
第四章 文件与目录
函数stat、fstat、fstatat和lstat
头文件:<sys/stat.h>
- 返回文件的stat信息
- struct stat {
文件类型
头文件:<sys/stat.h>
- 以stat中mode判断的文件类型
- 以结构体指针判断的文件类型
文件系统
目录读取
头文件:<dirent.h>
- readdir(DIR *dp),每次用目录中取出一项直到返回值为NULL
- dirent结构与实现有关,实现此结构的定义至少包括下列两个成员
ino_t d_ino // i节点
char d_name[]; // 文件名
第五章 标准IO库
标准输入,标准输出和标准错误
第六章 系统数据文件与信息
口令文件
头文件<pwd.h>
- /etc/passwd文件中的字段
- POSIX.1定义了获取口令文件项的函数
struct passwd* getpwuid(uid_t uid) //通过uid
struct passwd *getpwnam(const char *name) //通过登录名
阴影文件
头文件<shadow.h>
- /etc/shadow文件中的字段
- 错误返回NULL
组文件
头文件<grp.h>
- 具体函数形式同上
时间和日期例程序
头文件<time.h> <sys/time.h>
- 支持通过参数格式化产生的字符串
- 字符串转时间
- 时间日期格式化标识符
第七章 进程环境
进程终止
头文件<stdlib.h> <unistd.h>
- <stdlib.h>
void exit (int status);
void _Exit(int status);
<unistd.h>
void _exit(int status);
_exit 和 _Exit立即进入内核
exit先执行一些清理处理,然后返回内核
- <stdlib.h>
int atexit (void (*func)(void))
登记退出处理程序,exit调用这些函数从顺序与它们登记时候的顺序相反 - C程序的启动和终止
储存空间布局
储存空间分配
头文件<stdlib.h>
函数 setjmp和longjump
头文件<setjmp.h>
- env的类型是一个特殊类型,通常将其设定为全局变量
- 当longjmp返回到main函数所示,变量的值恢复情况变化是不确定的
函数getrlimit和setrlimit
头文件<sys/resource.h>
- 成功返回0,失败非0
- 对应rlimit结构
第八章 进程控制
函数fork
头文件<unistd.h>
- pid_t fork(void)
子进程返回0,父进程返回子进程ID(大于0),若出错,返回-1
子进程获得父进程数据空间、堆和栈的副本(不共享) - 文件共享
子进程与父进程共享一个文件表项,也就是说,子进程与父进程的读写偏移量保持一致 - 要使其保持不一致可以先用dup2函数获得一个指向同一个流的fd
函数vfork
头文件<unistd.h>
- 与fork不同的地方:
1.子进程在父进程的空间内运行
2.保证子进程先运行,在子进程调用exec或exit之间父进程都被阻塞。调用之后父进程恢复运行。
函数exit
头文件<stdlib.h><unistd.h>
- 进程的最后一个线程return返回值不作为进程的返回值,改终止状态为0
- 三种异常终止:
abort 产生SIGABRT信号
进程接收到某些信号且信号的处理程序为结束改进程
最后一个线程对“取消”请求作出响应
函数wait和waitpid
头文件<sys/wait.h>
- #include <sys/wait.h>
pid_t wait (int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int option)
成功返回0,出错返回0或者1 - option常量
- waitid函数提供了更多的灵活性,可以指定等待子进程的限制
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
函数exec
头文件<unistd,h>
- 7个exec函数之间的关系
解释器文件
头文件<unistd.h>
- 解释器文件是文本文件,其起始行的形式是:
#! pathname [optional-arguments]
pathname指向解释器 - 注意用execl执行时,第一个参数应该为执行文件名
函数system
头文件<stdlib.h>
- 函数形式
int system(const char *cmdstring)
第九章 进程关系
终端登录与网络登录
- 终端登录
- 完成login之后的进程安排
- 网络登录
- 网络登录后的进程安排
进程组与会话
头文件<unistd.h>
- int setpid(pid_t pid, pid_t pgid);
一个进程只能为他自己或他的子进程设置进程组id,当它的子进程调用exec后,不能再更改它的组id - 会话是一个或多个进程组的集合
- 进程调用setsid建立一个新会话
pid_t setsid(void)
如果该进程不是进程组的组长,则他会创建一个新会话,并变成会话首进程。
控制终端
- 如果一个会话有一个控制终端,则它有一个前台进程组,其他进程组为后台进程组 。
键入终端的中断键或者退出键,都会讲信号发送至前台进程组的所有进程。
作业控制
第十章 信号
信号概念
- Unix系统信号
- SIGCHLD信号:子进程终止或停止时,SIGCHLD被送给其父进程
SIGUSR1和SIGUSR2为用户定义的信号,可用于应用程序
函数signal
头文件<signal.h>
- 函数形式
void (*signal(int signo, void (*func)(int)))(int);
成功返回一千的信号处理配置,出错则返回SIG_ERR - exec 函数将原先设置为要捕捉的信号都更改为默认动作,其他信号的状态则不变(一个进程原先要捕捉的信号,当其执行一个新程序后,就不能再捕捉了,因为信号捕捉函数的地址很可能在所执行的新程序文件中已无意义)。
可重入函数
- 可重入函数
函数kill和raise
函数pause和alarm
头文件<signal.h>
- 函数形式
int kill(pid_t pid, int signo);
int raise(int signo); - pid值根据不同值有不同含义
0 发送至指定进程组
=0 发送至同一进程组的所有进程
<0 发送至进程组id为-pid的所有进程(要有权限)
- int pause(void)
只有执行了一个信号处理程序并返回,pause才返回,返回值为-1 - unsigned int alarm(unsigned int seconds);
经过second产生SIGALARM信号,其默认处理是终止进程
信号集
头文件<signal.h>
- 五个处理信号集的函数,各函数功能从函数名称可推断出
- 函数sisprocmask
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset)
how参数功能如下 - 函数sigpending
int sigpending(sigset_t *set);
返回当前未决的信号
函数sigaction
函数sigsetjmp和siglongjmp
函数sigsuspend
头文件<signal.h>
- 函数形式
int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
以一个信号处理结构简化了屏壁值设定以及替代了早期的signal函数 - 与setjmp唯一区别是带了mask参数,使得跳转的时候能恢复保存的信号屏蔽字
- 恢复信号屏蔽字然后进程休眠等待信号操作(原子操作以防信号丢失)
int sigsuspend(const sigset_t *sigmask);
返回值-1并将errno设置为EINTR
作业控制信号
- SIGCHLD 子进程已停止或终止。
SIGCONT 如果进程已停止,则使其继续运行。
SIGSTOP 停止信号(不能被捕捉或忽略)。
SIGTSTP 交互式停止信号。
SIGTTIN 后台进程组成员读控制终端。
SIGTTOU 后台进程组成员写控制终端。
第十一章 线程
线程创建与终止
头文件<pthread.h>
- 线程id只在当前进程上下文中才有意义,其数据类型为pthread_t,不能作为整数处理进行比较操作。int pthread-euqal( )进行比较操作。当前线程打印其线程id
pthread_t pthread_self(void); - 线程创建:
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void (start_rtn) (void), void *restrict arg);
其中:
tidp: 线程id所处的内存单元
attr:一系列线程属性
startrtn:线程开始运行的函数地址,只有一个无类型指针参数
arg:函数开始地址的函数参数补充 - 线程终止:
线程有三种推出方式:
- 简单的从启动例程中返回,返回值为线程的退出码。
- 可以被同一进程的其他线程所取消。
- 线程调用pthread_exit退出
- void pthread_exit(void *rval_ptr);
其他进程访问rval_ptr(返回状态内存单元?)
int pthread_join(pthread_t thread, void **rval_ptr);
进程同步
头文件<pthread.h>
- 互斥量创建与销毁:
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex即初始化的锁, attr为其相关属性 - 如果线程不希望被阻塞,它可以使用 pthread_mutex_trylock 尝试对互斥量进行加锁。如果调用 pthread ute _trylock 时互斥蜇处于未锁住状态,那么 pthread_mutex trylock将锁住互斥械,不会出现阻塞直接返回 0, 否则 pthread mutex_trylock 就会失败,不能锁住互斥量,返回 EBUSY
- 读写锁:
形式上与互斥量类似,但是并行度要更高
lock-> rlock wlock - 条件变量:
等待的参数为一个条件变量,条件变量本身是受互斥量保护的。
lock -> cond - 自旋锁:
与互斥量类似,但是不是通过互斥量类似的休眠机制。而是在获取锁之前一直处于忙等状态。适用于只持有锁一小段时间且不想进程调用所带来开销的场景:
非抢占式内核非常有用,但是在用户层效率一般(时间片机制阻塞)
lock -> spin - 屏障:等待直到所有进程都达到某一点, count规定达到的线程数量
第十二章 线程控制
线程属性
头文件 <pthread.h>
- init函数可以修改线程属性默认值
- 如果线程不需要了解线程的终止属性,可以修改pthread_attr_t结构中的 detachstate属性,可以设置为PTHREAD_CREATE_DETACHED和PTHREAD_CREATE_JIONABLE。下面函数可以获取、修改当前线程detachstate线程属性
同步属性
头文件 <pthread.h>
- 类似于线程属性,同步属性可以用init函数进行默认同步属性的初始化和反初始化 attr-> mutexattr
- 同步属性中四个重要的属性值:(都相应的可以用pthread_mutexattr_get***)进行获得和修改:
1:共享属性 get(set)pshared 如果设置为PTHREAD_PROCESS_SHARED,从多个线程共享的内存数据块中的互斥量(读写锁/条件变量/屏障)就可以用于这些线程的同步。
2:健壮性属性 get(set)robust 处理但一个持有互斥量的线程终止导致其他线程长时间阻塞的问题。终止时并没有对该锁进行解锁,此时线程会阻塞,pthread_mutex_lock 返回的值为 EO ERDEAD 而不是0. 线程可以调用pthread_mutex_consistent(pthread_mutex_t *mutex);使得互斥量恢复可用,并指明线程状态与解锁前是一致的。
3:时钟属性 get(set)lock : 规定pthread_cond_timedwait所采用的是哪个时钟
4:类型属性 settype 定义了一些加锁和解锁的一些限制:
线程特定(私有数据)数据
- 在分配特定数据之前,需要创建与该数据关联的键,键用于获取对线程特定数据的访问
- 键一旦创建以后,就可以通过调用 thread_setspecific 函数把键和线程特定数据关联起来。可以通过 pthread getspecific 函数获得线程特定数据的地址:
线程与信号/fork/IO
头文件:<pthread.h> <unistd.h>
- 每个线程都有自己的信号屏蔽字,但是对于信号的处理是所有线程共享的,线程的屏蔽字设置函数如下:
- 向单个线程发送信号:
int pthread_kill (pthread_t thread, int signo); - 在子进程 只存在 个线程,它是由父进程中调用 fork 的线程的副本构成的 如果父进程中的线程占有锁,子进程将同样占有这些锁 问题是子进程并不包含占有锁的线程的副本,所以子进程没有办法知道它占有了哪些锁、需要释放哪些锁.清除锁状态的函数:
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void) );
prepare fork处理函数由父进程在fork创建子进程之前调用,任务是获取父进程定义的锁。parent fork为fork创建子进程之后,返回上下文之前在父进程调用的,任务是对prepare fork确定的所有锁进行解锁。child fork是返回子进程上下文之前在子进程调用的,任务与parent一致。
- pread pwrite为原子操作,可以解决并发线程对同一文件进行读写的一致性问题
第十三章 守护进程
守护进程的特征
- 守护进程(daemon)是没有控制终端,在后台运行,仅在系统关闭时才终止的进程,Unix系统有很多守护进程,执行日常事务
编程规则
头文件 <stdlib.h> <unistd.h>
- 1:调用umask将文件模式设置为一个已知值
2:调用fork,然后使父进程exit。目的是确保进程不是一个进程组的组长进程。
3:调用setsid创建一个新会话,然后此进程成为新会话的首进程,成为一个新进程组的组长进程,同时没有控制终端。
4:将当前工作目录更改为根目录。
5:关闭不需要的文件描述符。
6:将文件描述符 0、1、2由原来的标准输入 输出 更改为/dev/null 使其输入输出错误均与终端无关
出错记录
头文件 <syslog.h>
- syslog:一个集中守护进程出错记录措施
上图分别对于三种产生日志消息的方法。
1:调用syslog(3) 函数产生日志消息,使得该消息发送至Unix域数据报套接字 /dev/log
2:将日志消息发送至UDP端口514.
3:内核例程调用log函数。 - syslogd读取所有三种格式的日志消息。该守护进程启动时会读取/etc/syslog.conf以确定不同种类的消息该送往何处。syslog函数如下:
openlog函数中,可以指定一个ident,通常是程序的名称。此名称将加至每则日志消息中;option定义了一些选项说明。
守护进程惯例
- 1:若守护进程使用锁文件,那么改文件一般储存与/var/run中,守护进程需有root权限才能彩瓷目录创建文件
2:若守护进程支持配置选项,那么配置文件通常存放在/etc文件夹中,其配置文件名字通常是name.conf
3:守护进程通常是由系统初始化脚本进行启动的(/etc/rc或/etc/init.d/)
4:如果一个守护进程有一个配置文件,那么该进程一般会在进程启动时读取,中途变更配置文件守护进程不能及时进行更改。
第十四章 高级IO
fcntl纪录锁
头文件 <fcntl.h>
- fcntl纪录锁原型:
int fcntl (int fd, int cmd, …/* struct flock * flockptr */);
其中 fd为文件标识符, cmd为F_GETLK、F_SETLK、或F_SETLKW,第三个参数为指向一个flock参数的指针
- flock结构及类成员说明:
type:所希望的锁类型,共享读、独占性或解锁一个区域
whence:解锁区域字节偏移量 start:加锁区域字节偏移量
len:区域字节长度 l_pid:pid为该值的持有的锁能阻塞当前进程 - fcntl三种命令:
F_GETLK:判断有flockptr所描述的锁是否会被排斥,若是,则阻止创建flockptr所描述的锁,并将改锁的信息重写flockptr;如果不是,则将flockptr所描述的锁l_type设置为F_UNLCK
F_SETLK:设置锁,若系统阻止,函数立即范围,errno设置为EACCES或EAGAIN
F_SETLKW:FSETLK的阻塞版本,系统阻止后该调用进程休眠,知道创建的锁可用进程被唤醒 - 继承关系
1:纪录锁与文件相关,当一个文件关闭,任何指向该文件的文件描述符都会失效
2:子进程不会继承父进程所获得的锁 - 建议性锁和强制性锁
建议性锁一般用在合作进程。并且没有其他方式对文件进行读写时使用,内核在加锁之后不会负责检查。(性能好)
强制性锁会让内核检查每一个open、read和、write以验证调用进程是否违背了正在访问该文件的某一把锁
I/O多路转接
头文件 <sys/select.h> <poll.h>
- 函数select
maxfdp1是描述符集中最大描述符, readfds writefds exceptfds分别对于 读 写 和 异常描述符集, tvptr为0时函数不等待直接返回, tvptr不为0时,当指定描述符之一或等待超过指定的时间是返回, 为NULL时则永远等待直到捕捉到一个指定的可用信号 - 函数poll
poll不是为每个条件构造一个描述符集,而是构造一个pollfd结构数组:
struct pollfd {
int fd;
short events;
short reventsl
} ;
异步I/O
头文件 <signal.h>
-
select和poll可以实现异步形式的通知,而信号机构提供了一种异步形式通知某种时间已发送
-
System V异步I/O:
STREAMS系统的一部分,需要调用ioctl并将其第二个参数(request)设置为I_SETSIG,指定SIGPOLL信号的条件,并且在调用ioctl之前建立信号处理程序 -
BSD异步I/O:
BSD派生系统中,SIGIO是通用异步信号,SIGURG用来通知网络连接带外数据到达 -
POSIX异步I/O
POSIX为不用类型的文件进行异步I/O提供了一套一致的方法
头文件 <aio.h>- 异步I/O接口使用AIO控制块来描述I/O操作
aio_filedes为打开用来读或写的文件描述符
_offset指定读或写的偏移量
_buf为读入后存放或写入来源的缓冲区
_nbytes为_buf缓冲区大小
_reqprio为请求提示顺序
_sigevent为字段控制,描述I/O时间结束后如何提示应用程序 - sigevent结构:
_notify:SIGEV_NONE,完成后不通知进程;SIGEV_SIGNAL,I/O完成后,由_signo指定的信号来通知应用程序;SIGEV_THREAD,I/O操作完成时,将调用_function,属性由_attributes指定,默认该函数将在分离状态下的一个单独线程中运行 - 相关函数
读写操作:
int aioread(struct aiocb *aiocb);
int aiowrite(struct aiocb *aiocb);
设置同步:
int aio_fsync(int op struct aiocb *aiocb);
获取完成情况:0 完成
int aio_error(const struct aiocb *aiocb);
阻塞进程知道所有异步I/O完成:
int aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timeout)
- 异步I/O接口使用AIO控制块来描述I/O操作
储存映射I/O
头文件 <sys/mman.h>
- 功能:存储映射 ( memory-mapped )能将一个磁盘文件映射到存储空间中的某个缓冲区上。于是,当从缓冲区中取数据时,就相当于读文件中的相应字节。可以在不适用write和read的条件下执行I/O
- mmap函数
void *mmap(void *addr, size_t len. int prot, int flag, int fd, off_t off );
addr len为映射区的起始地址和映射长度
prot参数指定了映射保护区的保护要求: PROT_READ 可写 PROT_WRITE PROT_EXEC可执行 PROT_NONE 不可访问
fd为指定文件的文件描述符
off为读取文件的偏移量,flag参数对应属性如下
MAPFIXED 返回值必须等于addr(即最终映射的地址与函数参数传入的建议地址必须一致,若未指定,函数将传入的attr地址作为一种建议,不代表最终引用)
MAP_SHARED / MAP_PRIVATE必须指定这两者其中一个,当程序修改映射程序时,前者指定修改映射文件而后者不影响映射文件,只对副本进行修改。 - 更改现有映射的权限:
int mprotect(void *addr, size_t len, int prot);
同步映射的页与该文件:
int msync(void *addr, size_t len, int flags);
解除映射:
int nunmap(void *addr, size_t len)
第十五章 进程间通信
管道
头文件 <unistd.h>
-
创建:pipe函数
int pipe(int fd[2]);
fd[0]为读而打开,fd[1]为写而打开 -
函数popen 和 pclose
FILE *popen(const char *cmdstring, const char *type);
int pclose(FILE *fp); 作用如下图所示 -
协同进程:
- 当一个过滤程序既产生某个过滤程序的输入,又读取该过滤程序的输出时,它就变成了协同进程。如下图:
- FIFO:相较于只能用在两个相关进程的普通管道,FIFO能使两个不相关的进程也能交换数据,FIFO是一种文件类型,具体创建函数如下。
XSI IPC
头文件 <sys/ipc.h>
- XSI IPC代表三种通信机制:消息队列,信号量与共享内存。依托标识符和键来实现:
- 内核为每一个进程维护一个结构体形式的IPC对象,对象通过一个非负整数的IPC标识来引用
- 若多个进程需要在同一个IPC对象上回合,则需要通过键值来引用该对象。
- ipc_perm结构:
消息队列
头文件 <sys/msg.h>
- 相应操作与函数:
msgget用于用键打开或者创建一个新的id,获得消息队列标识符msqid,每一个队列都有一个msqid_ds结构与其相关联。msgctl用处获得或者修改此结构相关属性,msgsnd用于将新消息发送至队列微端,msgrcv用于从队列中取消息。 - int msgget(key_t key, int flag); flag用于设置读写mode
int msgctl(int msqid, int cmd, struct msqid_ds *buf); IPC_STAT/SET/RMID
int msgsnd(int msqid, const void *ptr, size_t nbytes, int flag);
ssize_t msgrcv(int msqid, void *ptr, size_t nbytes, long type, int flag);
type指定消息种类, flag值指定操作是否可阻塞。
信号量
头文件 <sys/sem.h>
- 信号量为一个计数器,用于为多个进程提供对共享数据对象的访问
共享存储
头文件 <sys/shm.h>
- XSI共享存储为内存的匿名段,与存储映射不同,没有显式的文件
- int shmget (key_t key, size_t size, int flag); flag用于设置读写mode
int shmctl(int shmid, int cmd, struct shmid_ds *buf); IPC_STAT/SET/RMID
void *shmat(int shmid, const void *addr, int flag); 将此段连接到addr地址上
int shmdt(const void *addr);将段与地址分离
POSIX信号量
头文件
-
相较于SIX信号量接口,POSIX信号量接口更简单,更高性能,同时被删除时,表现更完美。POSIX信号量有命名和未命名两个版本,其中未命名版本只能用于同一进程的两个线程,而命名版本无此限制。
-
命名版本信号量
- sem_t *sem_open(const char *name, int oflag, … , mode_t mode, usigned int value);
semopen用于创建或打开一个命名信号量,信号量由name指定,mode用于指定用户组群读写权限, oflag指定创建或者是打开,value设定信号量初值 - int sem_close(sem_t *sem)
sem_close用于释放任何信号量相关的资源 - int sem_unlink(const char *name)
sem_unlink用于销毁一个命名信号量
- sem_t *sem_open(const char *name, int oflag, … , mode_t mode, usigned int value);
-
非命名信号量
- int sem_init(sem_t *sem, int pshared, unsigned int value);
pshared非零表示在多个进程中使用该信号量,此时要确保sem指向两个进程之间共享的内存范围。 - int sem_destroy(sem_t *sem)
- int sem_init(sem_t *sem, int pshared, unsigned int value);
-
共有操作
- int sem_trywait(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict tsptr);
三者均完成信号量的减一操作,trywait在信号量为0时立即返回-1并将errno置为EAGAIN, wait在信号量为0时发生阻塞,直到成功使信号量减一,第三个则在信号量为0时选择阻塞一定的时间,如果超期返回-1并将errno置为ETIMEOUT。 - int sem_post(sem_t *sem);
信号量增一操作 - int sem_getvalue(sem_t *restrict sem ,int *restrict valp);
取得信号量的值,放入valp所指的内存单元中
- int sem_trywait(sem_t *sem);
第十六章 网络IPC:套接字
见《Unix网络编程》笔记
第十七章 高级进程间通信
Unix域套接字
头文件 <sys/socket.h> <sys/un.h>
- 一对相互连接的Unix域套接字可以起到全双工管道的作用: 两端对读和写开放,创建方式:
int socketpair(int domain, int type, int protocol, int sockfd[2]); - Unix域套接字地址格式
struct sockaddr_un{
sa_family_t sun_family;
char sun_path[108];
};
当一个地址绑定到一个unix域套接字时,系统会用该路径名创建一个S_IFSOCK类型的文件