Linux 编程

Linux 进程存储管理

存储类型比较

类型 作用域 生存域 存储位置
auto 变量 一对 {} 当前函数 变量默认存储类型,存储在栈区
extern 函数 整个程序 整个程序运行期 函数默认存储类型,代码段
extern 变量 整个程序 整个程序运行期 初始化在 data 段,未初始化在 BSS 段
static 函数 当前文件 整个程序运行期 代码段
static 全局变量 当前文件 整个程序运行期 初始化在 data 段,未初始化在 BSS 段
static 局部变量 一对 {} 整个程序运行期 初始化在 data 段,未初始化在 BSS 段
register 变量 一对 {} 当前函数 运行时存储在 CPU 寄存器中
字符串常量 当前文件 整个程序运行期 代码段

栈和堆的区别

项目
管理方式 系统自动管理 手动管理
空间大小 小,向低地址扩展,连续的内存区域 大,向高地址扩展,不连续的区域,系统使用链表存储空闲内存地址
产生碎片
增长方向 向下,地址减小的方向 向上,地址增加的方向
分配方式 操作系统自动完成,也可以使用 alloca() 手动申请 使用 malloc() 申请, free() 释放
分配效率

内存空间申请释放相关函数

void * malloc (size_t size)
  • size: 申请的字节数
  • return: 指向所分配的空间首地址的指针。分配失败时返回 NULL。
void free (void *ptr)
  • ptr: 要释放的空间首地址

推荐释放后将指针置为空 ptr = NULL

void * realloc (void *ptr, size_t newsize)
  • ptr: 试图更改大小的堆空间位置
  • newsize: 新的内存大小
  • return: 新的内存指针,如果申请失败将返回 NULL,但原来的地址可以继续使用
void * calloc (size_t count, size_t eltsize)

类似 malloc ,会把动态分配的内存初始化为 0

void *alloca(size_t size);

在栈中分配空间,函数返回时会自动释放

内存数据管理函数

void * memcpy (void *restrict to, const void *restrict from, size_t size)
  • 复制后内存首地址
  • 数据源地址
  • return: 目的地址
void * memmove (void *to, const void *from, size_t size)

memcpy 相比,会检查源地址和目的地址是否重叠。

void * memset (void *block, int c, size_t size)

初始化指定内存单元

void *memchr(const void *s, int c, size_t n);

在一段内存空间中查找某个字符第一次出现的位置

int memcmp(const void *s1, const void *s2, size_t n);

strncmp 相同,比较内存单元 s1 和 s2 起始位置的前 n 个字节是否相等,相等返回 0;s1<s2,返回 -1;s1>s2,返回 1

进程与命令行相关函数

int getopt(int argc, char * const argv[], const char *optstring);
  • 参数个数
  • 指向参数的数组
  • 所有可能的参数字符串

getopt 函数的第 3 个参数 optstring 可以是下列元素:

  • 单个字符,这种表示选项。
  • 单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给 optarg(一个全局变量)。
  • 单个字符后跟两个冒号,表示该选项后可以跟一个参数。参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给 optarg
int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *indexptr)

第 1 个参数为当前传递进来的参数个数
第 2 个参数为当前传递进来的参数列表
第 3 个参数为当前进程所有可支持短参数的字符串
第 4 个参数为 struct option ,标识所有长参数的对应关系。
返回情况:

  • 在使用此函数处理一个参数时,全局变量 optarg 指向下一个要处理的变量,并返回 struct option 的第 4 个成员变量。一般情况下,如果 struct option 的第 3 个参数设置为 NULL,第 4 个参数一般设置为该长选项对应的短选项字符值,即返回相应的短选项字符。
  • 如果解析完最后一个成员将返回-1
  • 如果 getopt_long 遇到一个无效的选项字符,它会打印一个错误消息并且返回?
  • getopt_long 解析到一个长选项并且发现后面没有参数则返回:,表示缺乏参数。

环境变量相关函数

char * getenv (const char *name)

如果执行成功,此函数返回指定环境变量的值,否则返回 NULL

int putenv (char *string)

如果执行成功,将指定字符串信息添加到环境变量,该字符串格式为”NAME=VALUE”,如果没有后面的等号,则删除此环境变量。

int setenv (const char *name, const char *value, int replace)

第 1 个参数为欲设置的环境变量名
第 2 个参数为欲设置的值
第 3 个参数如果为非 0 且第 1 个指定的环境变量有一个存在值,将覆盖原来的值;如果第 3 个参数为 0 且第 1 个指定的环境变量有一个存在值,将保留原来值,并不返回错误

int unsetenv (const char *name)

删除某个环境变量的值

时间相关函数

clock_t clock (void)

返回当前时刻程序运行的时间(user time + system time),其结果为时钟计数器值,将其转换为秒的公式为: result / CLOCKS_PER_SEC

time_t time(time_t *tloc);

其时间是自 1970-1-1 0:0:0 以来经历的秒数。如果其参数设置为空,将返回时间秒数,如果参数不为空,将存储于该参数中。

char * ctime (const time_t *time)

返回当前时间字符串: Tue May 21 13:46:22 1991

struct tm * gmtime (const time_t *time)
struct tm * localtime (const time_t *time)

以上两个函数将返回 struct tm 结构体存储时间

char * asctime (const struct tm *brokentime)

此函数将 struct tm 结构体转换为标准时间字符串: Tue May 21 13:46:22 1991

size_t strftime (char *s, size_t size, const char *template, const struct tm *brokentime)

从 struct tm 中提取某一项。
第 1 个参数为存储某项的空间
第 2 个参数为该空间大小
第 3 个参数为欲提取的项
第 4 个参数为从哪个 struct tm 中提取
其中,第 3 个参数可提取项可为以下任意项:

占位符 替换 示例
%a 缩写的星期几名称 Sun
%A 完整的星期几名称 Sunday
%b 缩写的月份名称 Mar
%B 完整的月份名称 March
%c 日期和时间表示法 Sun Aug 19 02:56:02 2012
%d 一月中的第几天(01-31) 19
%H 24 小时格式的小时(00-23) 14
%I 12 小时格式的小时(01-12) 05
%j 一年中的第几天(001-366) 231
%m 十进制数表示的月份(01-12) 08
%M 分(00-59) 55
%p AM 或 PM 名称 PM
%S 秒(00-61) 02
%U 一年中的第几周,以第一个星期日作为第一周的第一天(00-53) 33
%w 十进制数表示的星期几,星期日表示为 0(0-6) 4
%W 一年中的第几周,以第一个星期一作为第一周的第一天(00-53) 34
%x 日期表示法 08/19/12
%X 时间表示法 02:50:06
%y 年份,最后两个数字(00-99) 01
%Y 年份 2012
%Z 时区的名称或缩写 CDT
%% 一个 % 符号 %

ANSI C 文件管理

指定流缓冲区

void setbuf (FILE *stream, char *buf)

第 1 个参数为要操作的流对象
第 2 个参数 buf 必须指向一个长度为 BUFSIZ 的缓冲区。如果将 buf 设置为 NULL ,则关闭缓冲区。

int setvbuf (FILE *stream, char *buf, int mode, size_t size)

第 1 个参数为要操作的流对象
第 2 个参数 buf 指向一个长度为第 4 个参数指示大小的缓冲区
第 3 个参数为缓冲区类型: _IOFBF_IOLBF_IONBF

文件 I/O 操作

FILE *fopen(const char *path, const char *mode);

第 1 个参数指向欲打开的文件名字符串的指针 ( /ect/services ),可以使用绝对路径或相对路径来指定
第 2 个参数为打开模式:

模式 说明
r 打开一个用于读取的文件。该文件必须存在。
w 创建一个用于写入的空文件。如果文件名称与已存在的文件相同,则会删除已有文件的内容,文件被视为一个新的空文件。
a 追加到一个文件。写操作向文件末尾追加数据。如果文件不存在,则创建文件。使用 fseek 修改无效
r+ 打开一个用于更新的文件,可读取也可写入。该文件必须存在。
w+ 创建一个用于读写的空文件。
a+ 打开一个用于读取和追加的文件。读位于文件头,写位于文件尾,使用 fseek 修改无效
int fclose (FILE *stream)

关闭该流对象

int fcloseall (void)

关闭打开的所有流对象

int fflush (FILE *stream)

更新缓冲区内容

int getc (FILE *stream)

若调用成功则返回读到的内容,如果失败或者读到文件结束则返回 EOF (-1)

int getchar (void)

相当于 getc(stdin)

int putc(int c, FILE *stream);

调用成功则返回内容,如果失败则返回-1

int putchar(int c);

相当于 putc(c, stdout)

char * fgets (char *s, int count, FILE *stream)
char * gets (char *s)

从将字符从 stream 读入 s 所指向的内存单元,直到读取 n-1 字符、换行符(传输到 s )或遇到文件结束标志 EOF 为止,并将最后一个空间置为 \0
gets() 不传输换行符。

int fputs(const char *s, FILE *stream);
int puts(const char *s);

puts() 将 s 指向的以空字符结尾的字符串(后接换行符)写入标准输出流 stdout。
fputs() 将 s 指向的以空字符结尾的字符串写入指定输出 stream ,但不追加换行符。

size_t fread (void *data, size_t size, size_t count, FILE *stream)

从流中读取 count 个大小为 size 的对象存放于第一个参数 ptr 所指向的内存空间。
第一个参数为读取的对象的存放位置
第二个参数为读取对象的大小,例如读出一个结构体 buf ,此参数可以设置为 sizeof(struct buf)

第三个参数为读取对象的个数
第四个参数为读取的流
返回实际读取到的对象个数(不是读写的字节大小)

size_t fwrite (const void *data, size_t size, size_t count, FILE *stream)

向流中写入 count 个大小为 size 的对象存储于 ptr 所指示的空间中。
第一个参数为指向欲写入的对象的数据空间指针,即写入的对象的存放位置
第二个参数为写入对象的大小,例如写入一个结构体 buf ,此参数可以设置为 sizeof(struct buf)

第三个参数为写入的个数
第四个参数为写入的数据流
执行成功返回实际写入的对象个数,否则返回 -1

int feof (FILE *stream)

用于二进制文件流,如果读到文件结束,返回 1 ,否则返回 0

int ferror (FILE *stream)

判断给定的流是否出现了错误,如果没有出现错误,返回 0 ,否则表示出错

void clearerr (FILE *stream)

清除错误标识位

long int ftell (FILE *stream)

返回流的当前读写位置距离文件开始的字节数

int fseek (FILE *stream, long int offset, int whence)

第一个参数为操作的流对象
第二个参数为针对第三个参数(修改基准)的偏移量
第三个参数为修改位置的基准: SEEK_SET 文件开头, SEEK_CUR 当前位置, SEEK_END 文件结尾

void rewind (FILE *stream)

将读写指针重置到文件开始位置

格式化输入输出

int printf (const char *template,)
int scanf (const char *template,)
int fprintf (FILE *stream, const char *template,)
int scanf (const char *template,)

printf() scanf() 函数专门针对标准输入输出流
fprintf() fscanf() 可用于任意流

int sprintf (char *s, const char *template,)

sprintf 是将列出的数据或者变量(第 3 个及后面多个参数)以 template 格式输出到以 s 为起始位置的内存空间中。
返回本次函数调用最终打印到字符缓冲区中的字符数目

int sscanf (const char *s, const char *template,)

scanf 类似,但以固定字符串为输入源

POSIX 文件与目录管理

文件流与文件描述符转换

int fileno (FILE *stream)

以某个流对象为参数,返回该流的文件描述符值。

FILE * fdopen (int filedes, const char *opentype)

将某个流与一个文件描述符相接。
第 1 个参数为一个文件描述符
第 2 个参数为封装该流的权限 ( r(+) , w(+) , a(+) )
成功返回一个流对象,失败返回 NULL

POSIX 标准下文件 I/O 管理

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

返回所打开的文件的文件描述符(int 类型)。
第 1 个参数是欲打开文件的文件路径
第 2 个参数打开文件的方式
如果欲打开的文件不存在,则可以使用 open 函数自动创建该文件,即 O_CREAT 打开方式,此时需要用到第 3 个参数,它约定了文件的权限,具体的计算方法为 mode&~umask

int close(int fd);

关闭文件,参数为调用 open 函数打开文件时返回的文件描述符

int creat(const char *pathname, mode_t mode);

创建文件,相当于 int open(const char *pathname, (O_CREAT|O_WRONLY|O_TRUNC), mode_t mode);

int fcntl (int filedes, int command,)

用于修改某个文件描述符的特殊属性
第 1 个参数 filedes 为欲修改属性的文件描述符
第 2 个参数 command 为相应操作

ssize_t read (int filedes, void *buffer, size_t size)

从参数 filedes 所指的文件中读取 size 数据到 buffer 指针所指的内存中,此函数返回值为实际读取到的字数。如果返回 0 ,表示已到达文件尾部或无数据可读。

ssize_t write (int filedes, const void *buffer, size_t size)

尝试将以 buffer 为起始地址的缓冲区前 size 个字节写入与打开文件描述符 filedes 关联的文件内。如果执行成功,将返回真正写入数据的大小,如果失败,将返回 -1 ,并置错误信息。

off_t lseek (int filedes, off_t offset, int whence)

第 1 个参数 filedes 为已经打开的文件
第 2 个参数 offset 为根据参考位置来移动读写位置的偏移数
第 3 个参数 whence 参考位置: SEEK_SET 文件开头, SEEK_CUR 当前位置, SEEK_END 文件结尾
返回当前读写位置距离文件头的字节数

void sync(void);
int fsync(int fd);
int fdatasync(int fd);

更新缓冲区。
sync 始终成功,但 sync 只是将所有修改过的块的缓存排入写队列,然后返回,不等待实际 I/O 操作结束。
fsync 等待 I/O 结束,然后返回
fdatasync 只更新内容,如果没有必要,并不更新元数据
成功时返回 0

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);

将某个文件的指定内容映射到内存空间中。

int flock(int fd, int operation);  

对文件的锁定和解锁操作,其锁定针对相应的文件表项(struct file ),因此,复制的新文件描述符仍然受其影响。
第 1 个参数为欲操作的文件描述符
第 2 个参数为操作命令:

  • LOCK_SH:建立共享锁定。多个进程可同时对同一文件作共享读操作,但不能排它写锁定。
  • LOCK_EX:建立文件互斥锁定。任意两进程不能同时操作文件。
  • LOCK_UN:解除文件的锁定状态。
  • LOCK_NB:无法建立锁定时,此操作可不被阻塞,马上返回进程,通常与前面的操作组合使用。

目录流基本操作

DIR *opendir(const char *name);
int closedir(DIR *dirp);

opendir() 打开路径为 name 的目录,并使用一个目录流指针,用来标识后续操作中的目录流。
closedir() 用于关闭指定的目录流,然后释放与 DIR 指针关联的结构。

struct dirent *readdir(DIR *dirp);

每调用一次 readdir() ,其将返回指向下一个目录条目的指针。如果到达目录的结尾,或者检测到无效的 seekdir() 操作,将返回 NULL 指针。

int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

readdir() 在多线程操作中会不安全,因此,Linux 提供了 readdir_r() 函数实现多线程读取目录内容操作。
第 1 个参数为打开的目录指针,它将初始化第 2 个参数 entry 引用的 dirent 结构,以表示第 1 个参数 dirp 所引用的目录流中的当前位置;然后在第 3 个参数 result 所指示的位置存储指向该结构的目录信息。
如果成功完成,将在第 3 个参数返回一个指向描述目录条目的 struct dirent 类型对象的指针。如果到达目录的结尾,则在第 3 个参数中返回 NULL 指针,并返回 0

long telldir(DIR *dirp);

返回目录流相关联的当前位置。

void seekdir(DIR *dirp, long loc);

dirp 引用的目录流上设置下一个 readdir() 操作的位置。 loc 参数是从 telldir() 获取的目录流中的一个位置。只有当对应的 DIR 指针处于打开状态时,这些值才有效。如果将目录流关闭后再重新打开,其值可能无效。

void rewinddir(DIR *dirp);

dirp 引用的目录流的位置重置到目录的开头。

int mkdir (const char *filename, mode_t mode)
int rmdir (const char *filename)

第 1 个参数为欲创建的目录文件路径
第 2 个参数用于设置该目录的访问权限,新创建文件权限为 mode & ~umask & 0777

char *getcwd(char *buf, size_t size);
char *get_current_dir_name(void);

将当前工作路径的绝对路径名置于由 buf 所指定的数组中,并返回 bufsize 的数值至少比所返回路径名的长度大 1,否则返回 NULL

int chdir(const char *path); 
int fchdir(int fd);

修改当前进程工作路径

int chroot(const char *path);

修改一个进程可以访问的根目录路径

int isfdtype(int fd, int fdtype);

测试某个打开的文件描述符的原文件是什么类型

文件属性管理

int stat(const char *pathname, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);

第 1 个参数为欲读取状态的文件(路径字符串),可以使用绝对路径或相对路径
第 2 个参数为文件属性临时存放位置,其类型为 struct stat

读取已打开的文件可以使用 fstat 函数 。
如果 stat 函数的第 1 个参数为符号连接文件,其读取的属性为源文件的属性,要获取连接文件自身的属性,需要调用 lstat 函数。

int chmod(const char *pathname, mode_t mode);

第 1 个参数为要修改权限的文件名
第 2 个参数为修改的权限描述, mode_t 原始类型为 unsigned int

int chown (const char *filename, uid_t owner, gid_t group)
int fchown (int filedes, uid_t owner, gid_t group)

第 1 个参数为欲修改用户的文件
第 2 个参数为修改后的文件拥有者 ID
第 3 个参数为修改后该文件拥有者所在的 GID

int link (const char *oldname, const char *newname)
int unlink (const char *filename)

创建硬连接文件
第 1 个参数为源文件的路径
第 2 个参数为新硬连接文件的路径

int symlink(const char *target, const char *linkpath);

创建符号连接
第 1 个参数为源文件的路径
第 2 个参数为新连接文件的路径

ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

将指定符号连接文件的源文件路径读入到 buf
第 1 个参数为符号连接文件路径
第 2 个参数为存储源文件路径的内存起始地址
第 3 个参数为可用空间大小

int utime (const char *filename, const struct utimbuf *times)

修改文件的访问时间和修改时间

进程管理

pid_t getpid(void);
pid_t getppid(void);

获得当前进程号或父进程号

pid_t getpgid(pid_t pid);
pid_t getpgrp(void);

getpgid() 函数来获得指定进程的进程组号。参数 pid 为要获得进程组号的进程号,如果为 0 表示获取当前进程组号。
getpgrp() 也可以用来获取当前进程的进程组号。

int setpgid(pid_t pid, pid_t pgid);

将某个进程加到某个进程组。
第 1 个参数为欲修改进程 PGID 的进程 PID
第 2 个参数为新的进程组号
如果这两个参数相等,则由 pid 指定的进程变成进程组组长;如果 pid0 ,则修改当前进程的 PGID;如果 pgid0 ,则由 pid 指定的进程的 PID 将用于进程组号 PGID。

pid_t getsid(pid_t pid);

如果 pid0 ,返回调用进程的会话号 SID,一般来说,该值等于进程组号 PGID。如果 pid 并不属于调用者所在的会话,则调用者就不能获得 SID。

pid_t setsid(void);

创建新会话。

pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
pid_t tcgetsid(int fd);

tcgetpgrp() 返回与打开的终端 fd 相关联前台进程组的进程组号。
tcsetpgrp() 用来设置某个进程组是前台还是后台进程组
tcgetsid() 可以获取控制终端的会话首进程的会话 ID

uid_t getuid(void);
uid_t geteuid(void);

获得当前进程的 RUID
获得当前进程的 EUID

gid_t getgid(void);
gid_t getegid(void);

获得当前进程的 GID
获得当前进程的 EGID

pid_t fork (void)
pid_t vfork (void)

如果执行成功,在父进程中返回新进程的 PID,在子进程中返回 0
如果执行失败,则在父进程中返回 -1
vfork() 函数创建新进程时不复制父进程的地址空间。

int execl (const char *filename, const char *arg0,)
int execlp (const char *filename, const char *arg0,)
int execle (const char *filename, const char *arg0,, char *const env[])
int execv (const char *filename, char *const argv[])
int execvp (const char *filename, char *const argv[])
int execve (const char *filename, char *const argv[], char *const env[])
  • v: 使用 argv 参数数组
  • l: 使用参数列表
  • p: 搜索 PATH 环境变量查找程序
  • e: 设置环境变量
int system(const char *command);

创建新进程,并在此进程中运行新进程,直到新进程结束后,才继续运行父进程。

int atexit(void (*function)(void));
int on_exit(void (*function)(int , void *), void *arg);

注册在执行 exit() 函数前执行的操作函数。
atexit 注册的函数没有参数, on_exit 注册的函数带参数。
第 1 个参数为退出的状态,在执行 exit() 函数时此参数值为 exit() 函数的参数。
第 2 个参数为用户输入的信息,一个无类型的指针。用户可以指定一段代码位置或输出信息。

void exit(int status);
void _exit(int status);

_exit 函数不调用任何注册函数而直接退出进程。

pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);

调用 wait() 函数的父进程将阻塞式等待该进程的任意一个子进程结束后,回收该子进程的内核进程资源。
返回当前结束的子进程的 PID,同时将子进程退出时的状态存储在 _stat_loc 变量中。

waitpid() 函数来等待指定子进程结束。
第 1 个参数为进程 PID 值:

  • PID > 0:等待进程 PID 为该 PID 值的进程结束
  • PID = -1:等待任意子进程结束,相当于调用 wait 函数
  • PID = 0:等待与当前进程的进程组 PGID 一致的进程结束
  • PID < -1:等待进程组 PGID 是此值的绝对值的进程结束

第 2 个参数为调用它的函数中某个变量地址,如果执行成功,则用来存储结束进程的结束状态。
第 3 个参数为等待选项,可以设置为 0 ,亦可为 WNOHANG (不阻塞等待)和 WUNTRACED (报告状态信息)

int access(const char *path, int amode);

用来检查当前进程是否拥有对某文件的相应访问权限。
第 1 个参数为欲访问的文件(包含路径)
第 2 参数为相应的访问权限

int setuid(uid_t uid);  
int setgid(gid_t gid);  

设置进程真实用户 RUID。
如果当前用户是超级用户,则将设置真实用户号(UID)、有效用户号 EUID 为指定 ID,并返回 0 以标识成功。
如果当前用户是普通用户,且欲设置的 UID 值为自己的 UID,则可以修改成功,否则无权修改,函数将返回 -1
setgid 类似。

int seteuid(uid_t euid); 
int setegid(gid_t egid);

设置进程有效用户 EUID
如果是超级用户,将设置有效用户号(EUID)为指定 ID。如果调用成功,该函数将返回 0 ;如果调用失败,将返回 -1 ,并有错误代码设置。
如果是普通用户,可以设置 EUID 为自己的 ID,如果想设置为其他用户,则不予更改,返回 -1

setegid 类似。

int setreuid(uid_t ruid, uid_t euid); 
int setregid(gid_t rgid, gid_t egid);

同时修改 UID/GID 和 EUID/EGID

void openlog(const char *ident, int option, int facility); 

打开当前程序与日志守候进程之间的联系
第 1 个参数:要向每个消息加入的字符串,一般可设置为为当前进程名
第 2 个参数:用来描述已打开选项
第 3 个参数:消息的类型,决定将消息写入到哪个日志文件中

void syslog(int priority, const char *format, ...); 

产生一条日志信息,然后由日志守候进程将其发布到各日志文件中
第 1 个参数决定日志级别
第 2 个参数为日志输出格式,类似于 printf 函数的第 2 个参数

进程间通信

管道

int pipe (int filedes[2])

创建无名管道
使用 readwrite 等函数进行读写操作,不能使用 lseek 函数来修改当前的读写位置,因为管道需要满足 FIFO 的原则。

int dup (int old)
int dup2 (int old, int new)

复制文件描述符

FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

流重定向

int mkfifo (const char *filename, mode_t mode)

创建有名管道
filename 为要创建的管道文件名
mode 为生成文件的权限
在通过 writeread 系统调用来执行读写操作前,需要调用 open() 函数打开该文件
操作有名管道的阻塞位置为 open 位置,而不是无名管道的读写位置。

信号

int kill(pid_t pid, int sig);

第 1 个参数为要传递信号的进程号
第 2 个参数为发送的信号值
pid 可以取以下几种值:

  • pid > 0:将信号发送给进程的 PID 值为 pid 的进程。
  • pid = 0:将信号发送给和当前进程在同一进程组的所有进程。
  • pid = -1:将信号发送给系统内的所有进程。
  • pid < 0:将信号发送给进程组号 PGID 为 pid 绝对值的所有进程。
int raise(int sig);

给当前进程发送一个信号

unsigned int alarm(unsigned int seconds);

在多少时间(秒为单位)内发送 SIGALRM 信号给当前进程,默认情况下,当进程接收到 alarm 信号后将终止执行。

  • 如果 sec0,则取消所有先前发出的报警请求。
  • 如果在调用 alarm() 函数前没有调用过 alarm() 函数,则执行成功返回值 0,否则返回-1,并设置 errno 标识错误。
  • 如果在此前调用过 alarm() 函数,则将重新设置调用进程的闹钟。如果执行成功,将以当前时间为基准,返回值为上次设置的 alarm() 将在多少时间内产生 SIGALRM 信号。如果执行失败返回-1,并设置 errno 标识错误。
useconds_t ualarm(useconds_t usecs, useconds_t interval);

使当前进程在指定时间(第 1 个参数,以 us 为单位)内产生 SIGALRM 信号,然后每隔指定时间(第 2 个参数,以 us 为单位)重复产生 SIGALRM 信号。

int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);

getitimer()setitimer() 根据逝去时间、在用户空间执行时间、总的执行时间来设置/读出超时定时器信息,定时器将在超时后产生相应的信号。

sighandler_t signal (int signum, sighandler_t action)

安装信号处理函数
第 1 个参数 signum 为接收到的信号
第 2 个参数为接收到此信号后的处理代码入口或下面几个宏:

  • SIG_ERR: 返回错误
  • SIG_DFL: 执行信号默认操作
  • SIG_IGN: 忽略信号

如果执行成功,此函数将返回针对此信号的上一次设置,如果设置多次,最终生效者为最近一次设置操作。如果执行失败,将返回 SIG_ERR 错误。

int sigaction (int signum, const struct sigaction *restrict action, struct sigaction *restrict old-action)

第 1 个参数为接收到的信号
第 2 个参数用来指定欲设置的信号处理方式
第 3 个参数将存储执行此函数前针对此信号的安装信息
第 2、3 个参数均为信号结构 sigaction 变量。

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

设置当前进程屏蔽的信号集合
第 1 个参数为更改该集的方式:

  • SIG_BLOCK:将第 2 个参数所描述的集合添加到当前进程屏蔽的信号集中
  • SIG_UNBLOCK:将第 2 个参数所描述的集合从当前进程屏蔽的信号集中删除
  • SIG_SETMASK:无论之前屏蔽了哪些信号,设置当前进程屏蔽的集合为第 2 个参数描述的对象

如果 set 是空指针,则参数 how 的值没有意义,且不会更改进程的屏蔽信号集,因此该调用可用于查询当前屏蔽的信号集合 ( oldset )

int sigpending (sigset_t *set)

获取当前未决的信号集合

int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigismember(const sigset_t *set, int signum);
int sigisemptyset(const sigset_t *set);
int sigandset(sigset_t *dest, const sigset_t *left, const sigset_t *right);
int sigorset(sigset_t *dest, const sigset_t *left, const sigset_t *right);

添加信号到信号集
从信号集中删除某个信号
清空信号集
填充所有信号到信号集
检测信号是否在信号集中
检测信号集是否为空信号集
按逻辑与方式将两个信号集合并
按逻辑或方式将两个信号集合并

int pause(void);

使当前进程处于等待状态,直到当前进程屏蔽信号外的任意一个信号出现

int sigsuspend(const sigset_t *mask);

将当前进程屏蔽的信号集替换为其参数所指定的信号集合,直到收到一个非指定集合中的信号后继续执行

消息队列

key_t ftok(const char *pathname, int proj_id);

创建 IPC KEY
pathname 为文件路径,一般使用当前目录 .

proj_id 为一个 int 型变量

int msgget(key_t key, int msgflg);

创建消息队列
第 1 个参数 key 为由 ftok 创建的 key 值
第 2 个参数 msgflg 的低位用来确定消息队列的访问权限,其最终权限为 perm & ~umask , 其高位包含以下项:

  • IPC_CREAT: 如果 key 不存在则创建,存在则返回 ID
  • IPC_EXCL: 如果 key 存在,返回失败
  • IPC_NOWAIT: 如果需要等待,直接返回错误
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

消息队列属性控制
第 1 个参数 msqid 为消息队列标识符,该值为使用 msgget 函数创建消息队列的返回值
第 2 个参数 cmd 为执行的控制命令,包括以下选项:

  • IPC_STAT:读取消息队列属性。取得此队列的 msqid _ds 结构,并将其存放在 buf 指向的结构中
  • IPC_SET:设置消息队列属性。按由 buf 指向的结构中的值,设置与此队列相关的结构中的下列 4 个字段:msg_perm.uidmsg_perm.gidmsg_perm、modemsg_qbytes。此命令只能由下列两种进程执行:一种是其有效用户 ID 等于 msg_perm.cuidmsg_perm.uid 的进程,另一种是具有超级用户特权的进程。只有超级用户才能增加 msg_qbytes 的值。
  • IPC_RMID:删除消息队列。从系统中删除该消息队列以及仍在该队列上的所有数据,这种删除立即生效。仍在使用这一消息队列的其他进程在它们下一次试图对此队列进行操作时,将出错返回 EIDRM。此命令只能由下列两种进程执行:一种是其有效用户号(UID)等于 msg_perm.cuidmsg_perm.uid 的进程,另一种是具有超级用户特权的进程。
  • IPC_INFO:读取消息队列基本情况。

这 4 条选项( IPC_STATIPC_SETIPC_INFOIPC_RMID )也可用于信号量和共享内存

第 3 个参数是一个临时的 msqid_ds 结构体类型的变量。用于存储读取的消息队列属性或者需要修改的消息队列属性。

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

发送信息到消息队列
第 1 个参数 msqid 为指定的消息队列标识符(由 msgget 生成的消息队列标识符)
第 2 个参数 msgp 指向的用户定义缓冲区,结构为:

struct msgbuf {
    long mtype;       /* message type, must be > 0 */
    char mtext[1];    /* message data */
};
  • mtype 是一个正整数,表示消息的类型,接收进程可以用来进行消息选择(消息队列在存储信息时是按发送的先后顺序放置的)
  • mtext 存储消息内容,在使用时自己重新定义此结构

第 3 个参数为接收信息的大小,其数据类型为 size_t ,即 unsigned int 类型。其大小为 0 到系统对消息队列的限制值
第 4 个参数用来指定在达到系统为消息队列所定的界限(如达到字数限制)时应采取的操作:

  • IPC_NOWAIT:如果需要等待,则不发送消息并且调用进程立即返回错误信息 EAGAIN
  • 0:如果需要等待,则阻塞调用进程
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

从消息队列接收信息
第 1 个参数为读的消息队列
第 2 个参数为一个临时消息数据结构,用来保存读取的信息。其定义 msgbuf 如上
第 3 个参数 msgsz 用于指定 mtext 的大小(以字节为单位)
第 4 个参数 msgtyp 用于指定请求的消息类型,具体如下所示:

  • msgtyp = 0:接收队列中的第一条消息,任意类型
  • msgtyp > 0:接收第一条 msgtyp 类型的消息
  • msgtyp < 0:接收第一条最低类型(小于或等于 msgtyp 的绝对值)的消息

第 5 个参数 msgflg 用于指定所需类型消息不在队列上时将要采取的操作。具体如下所示:

  • 如果设置 IPC_NOWAIT,如果现在没有消息,调用进程立即返回,同时返回-1,并将 errno 设为ENOMSG
  • 如果未设置 IPC_NOWAIT,则阻塞调用进程行,直至出现以下任何一种情况发生
    • 某一所需类型的消息被放置到队列中
    • msqid 从系统中删除。当该情况发生时,将 errno 设为EIDRM,并返回-1
    • 调用进程收到一个要捕获的信号。在这种情况下,未收到消息,并且调用进程按 signal (SIGTRAP)中指定方式恢复执行

返回接收到的消息大小

信号量

int semget(key_t key, int nsems, int semflg);  

创建信号量集合
第 1 个参数为 key_t 类型的 key
第 2 个参数 nsems 为创建的信号量个数,以数组的方式存储
第 3 个参数 semflg 用来标识信号量集合的权限,与消息队列的相同

int semctl(int semid, int semnum, int cmd, ...);

第 1 个参数 semid 为要操作的信号量集合标识符,该值一般由 semget 函数返回
第 2 个参数为集合中信号量的编号。如果标识某个信号量,此值为该信号量的下标(从 0n-1 );如果操作整个信号量集合,此参数无意义。
第 3 个参数为要执行的操作,如果是对整个信号量集合操作,则包括 IPC_RMIDIPC_SETIPC_STATIPC_INFO 。如果是对信号量集合中的某个或某些信号量操作,则包括:

  • GETPID: 获取信号量拥有者的 pid
  • GETVAL: 获取信号量的值
  • GETALL: 获取所有信号量的值,第 2 个参数为 0,第 4 个参数为存储所有信号量值内存空间首地址
  • GETNCNT: 获取等待信号量的值递增的进程数
  • GETZCNT: 获取等待信号量的值递减的进程数
  • SETVAL: 设置信号量的值
  • SETALL: 设置所有信号量的值,第 2 个参数为 0,第 4 个参数为欲设置的信号量值所在数组首地址
int semop(int semid, struct sembuf *sops, size_t nsops);

操作信号量集合
第 1 个参数为要操作的信号量集合 ID
第 2 个参数为 struct sembuf 结构的变量

共享内存

int shmget(key_t key, size_t size, int shmflg);  

创建共享内存
第 1 个参数为 key_t 类型的 key
第 2 个参数 size 为欲创建的共享内存段大小(单位为字节)
第 3 个参数 shmflg 用来标识共享内存段的创建标识,包括: IPC_CREAT IPC_EXCL IPC_NOWAIT SHM_R (可读) SHM_W (可写)

int shmctl(int shmid, int cmd, struct shmid_ds *buf);  

共享内存控制
第 1 个参数为要操作的共享内存标识符,该值一般由 shmget 函数返回
第 2 个参数为要执行的操作,包括 IPC_RMIDIPC_SETIPC_STATIPC_INFO

第 3 个参数为 struct shmid_ds 结构的临时共享内存变量信息,此内容根据第 2 个参数的不同而改变

void *shmat(int shmid, const void *shmaddr, int shmflg);

映射共享内存对象
将一个共享内存段映射到调用进程的数据段中,并返回该内存空间首地址
第 1 个参数 shmid 为要操作的共享内存标识符,该值一般由 shmget 函数返回
第 2 个参数 shmaddr 指定共享内存的映射地址。如果该值为非零,则将用此值作为映射共享内存的地址,如果此值为 0 ,则由系统来选择映射的地址。一般都将此值设置为 0

第 3 个参数用来指定共享内存段的访问权限和映射条件: 0 (读写) SHM_RND SHM_EXEC SHM_RDONLY SHM_REMAP

int shmdt(const void *shmaddr);

分离共享内存对象

线程

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

第 1 个参数用来存储线程 ID,参数为指向线程 ID 的指针,线程的 ID 在某个进程中是唯一的。如果创建成功,在此参数中返回新线程 ID;如果设置为 NULL ,则不会返回生成的线程的标识值
第 2 个参数用来设置线程属性,一般设置为 NULL ,新的线程将使用系统默认的属性
第 3 个参数是线程运行的代码起始地址
第 4 个参数是运行函数的参数地址。如果需要传入多个参数,则需要使用一个包含这些参数的结构体地址

void pthread_exit(void *retval);

结束一个线程,与进程调用 exit() 函数类似。参数为线程退出状态

int pthread_join(pthread_t thread, void **retval);

等待某线程结束,此函数将阻塞调用当前线程的线程,直到目标线程退出
第 1 个参数为被等待的线程 ID,此线程必须同调用它的进程相联系,而不能是独立的线程,默认情况下线程为关联线程,如果要设置某个线程为独立线程,则可以调用 pthread_detach() 函数
第 2 个参数为一个用户定义的指针,指向一个保存等待线程的完整退出状态的静态区域,它可以用来存储被等待线程的返回值

void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

线程取消时自动释放资源,采用先入后出的栈结构管理
routine 是要执行的清理函数, arg 为函数参数
execute 表示执行到 pthread_cleanup_pop() 时,是否在弹出清理函数的同时执行该函数, 0 表示不执行;非 0 为执行。

int pthread_cancel(pthread_t thread);

取消线程
一个线程能够被取消并终止执行需要满足以下条件:

  • 线程是否可以被其他取消,默认可以被取消。
  • 线程处于可取消点才能取消。也就是说,即使该线程被设置为可以取消状态,另一个线程发起取消操作,该线程也不是一定马上终止,只能在可取消点才终止执行。可以设置线程为立即取消或只能在取消点被取消。

执行取消操作时,将调用线程的 pthread_cleanup_push 函数。 pthread_cancel() 的调用者不会等待目标线程操作完成。

int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);

设置和查询当前线程的可取消性状态或类型

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

创建线程私有数据
该函数从 TSD 池中分配一项,将其地址值赋给 key 供以后访问使用。如果第 2 个参数不为空,在线程退出(调用 pthread_exit() 函数)时将以 key 所关联的数据为参数调用其指向的资源释放函数,以释放分配的缓冲区。
不论哪个线程调用 pthread_key_create() ,所创建的 key 都是所有线程可访问的,但各个线程可根据自己的需要往 key 中填入不同的值,相当于提供了一个同名而不同值的全局变量。

int pthread_key_delete(pthread_key_t key);

注销一个 TSD
不检查当前是否有线程正使用该 TSD,也不会调用清理函数(destr_function),只是将 TSD 释放以供下一次调用 pthread_key_create() 使用

int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key);

读写线程私有数据
pthread_setspecific()value 的值(不是所指的内容)与 key 相关联
pthread_getspecific() 函数将与 key 相关联的数据读出来
数据类型都设为 void* ,因此可以指向任何类型的数据

int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);

初始化和销毁互斥锁
第 1 个参数 mutex 是指向要初始化的互斥锁的指针
第 2 个参数 attr 是指向属性对象的指针,该属性对象定义要初始化的互斥锁的属性。如果该指针为 NULL ,则使用默认的属性

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

pthread_mutex_lock() 函数以阻塞方式申请互斥锁
pthread_mutex_trylock() 函数以非阻塞方式申请互斥锁
pthread_mutex_unlock() 函数用来释放互斥锁

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);

初始化和销毁条件变量
第 1 个参数 cond 是指向要初始化或损坏的条件变量的指针。
第 2 个参数 cond_attr 是指向属性对象的指针,该属性对象定义要初始化的条件变量的特性,如果该指针为 NULL ,则使用默认的属性。

int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

pthread_cond_signal() 函数用来通知等待条件变量的第 1 个线程。
pthread_cond_broadcast() 函数用来通知等待条件变量的所有线程。

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);

pthread_cond_wait() 函数用来阻塞等待某个条件变量
第 1 个参数 cond 是指向要等待的条件变量的指针。
第 2 个参数 mutex 是指向与条件变量 cond 关联的互斥锁的指针。

pthread_cond_timedwait() 函数将在指定的时间范围内等待条件变量
第 1 个参数 cond 是指向要等待的条件变量的指针。
第 2 个参数 mutex 是指向与条件变量 cond 关联的互斥锁的指针。
第 3 个参数 abstime 是等待过期时的绝对时间,如果在此时间范围内取到该条件变量函数将返回。该时间为从 1970-1-1 0:0:0 以来的秒数,即为一个绝对时间。

int pthread_kill(pthread_t thread, int sig);
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);

转载规则

《Linux 编程》Konata 采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
  目录