一. Linux 系统编程概论
1.1 系统编程基石
syscall:
libc: 标准 C 库, 系统调用封装, 线程库, 基本应用工具
gcc:
1.2 模块接口
API: 应用程序编程接口, 源代码级别, 能通过编译, 由标准 C 语言定义, libc 来实现
ABI: 应用程序二进制接口, 二进制级别, 能正常运行, 关注调用约定, 字节序, 寄存器使用, 系统调用, 链接, 二进制格式等, 很难实现
1.3 错误处理
- <stdio.h>
- errno:
- perror(const char *):
- <string.h>
- char * strerror (int errnum);
- int strerror_r(int errnum, char *buf, size_t len);
二. 文件管理
2.1 基本文件 I/O
2.1.1 open 系统调用
2.1.1.1 定义
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- int open(const char *name, int flags);
- int open(const char *name, int flags, mode_t mode);
2.1.1.2 flags 参数
O_RDONLY: 只读
O_WRONLY: 只写
O_RDWR: 读写
其它 O_XXX:APPEND, ASYNC, CREAT, DIRECT, DIRECTORY, EXCL, LARGEFILE, NOCTTY, NOFOLLOW, NONBLOCK, SYNC, TRUNC
2.1.1.3 mode 参数
文件权限, 例如 0777, 仅当 flags 包含标志 O_CREAT 时需要提供, 也是必须提供的
2.1.1.4 creat 函数
int creat(const char *name, int mode);
等价于
open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
2.1.2 read 系统调用
2.1.2.1 定义
- #include <unistd.h>
- ssize_t read(int fd, void *buf, size_t len);
2.1.2.2 返回值 ret = read(fd, buf, len)
1)ret == len: 调用正常, 结果和预期一致
2)0<ret < len: 信号打断了读取过程, 读取中发生错误, 已经到达文件末尾, 处理的办法是继续读取剩余的字节, 更新 buf 和 len
3)ret == 0: 已经到达文件末尾
4)ret == -1
errno == EINTR: 表示读入字节之前收到了一个信号, 可以重新调用
errno == EAGAIN: 在非阻塞模式下发生, 表示无数据可读
other: 发生了严重的错误
5)ret 无返回值: 阻塞了
2.1.2.3 阻塞读取示例
- while(len != 0 && (ret = read(fd, buf, len)))
- {
- if(ret == -1)
- {
- if(errno == EINTR)
- continue;
- perror("read");
- break;
- }
- len -= ret;
- buf += ret;
- }
2.1.2.4 非阻塞读取示例
- char buf[BUFSIZ];
- ssize_t nr;
- do
- {
- nr = read (fd, buf, BUFSIZ);
- if(nr == -1)
- {
- if(errno == EINTR)
- continue;
- if(errno == EAGAIN)
- {
- /* resubmit later */
- }
- else
- {
- perror("read");
- break;
- }
- }
- len -= ret;
- buf += ret;
- }
2.1.2.5 pread: 从指定的偏移量开始读取, 不改变当前文件偏移量指针, 可避免竞态的 lseek 调用
- #include <unistd.h>
- ssize_t pread(int fd, void *buf, size_t len, off_t pos);
2.1.3 write 系统调用
2.1.3.1 定义
- #include <unistd.h>
- ssize_t write(int fd, const char *buf, size_t count);
2.1.3.2 示例代码
- while(len != 0 && (ret = write(fd, buf, len)))
- {
- if(ret == -1)
- {
- if(errno == EINTR)
- continue;
- perror("write");
- break;
- }
- len -= ret;
- buf += ret;
- }
2.1.3.3 O_APPEND: 适用于日志类型的应用
2.1.3.4 延迟写
内核设定了缓冲数据刷新的超时时间, 由 / proc/sys/vm/dirty_expire_centisecs 定义
2.1.3.5 立刻写
1)int fsync(int fd): 刷新文件 fd 的数据和元数据
2)int fdatasync(int fd): 仅刷新文件 fd 的数据
3)void sync(void): 刷新所有的缓冲数据, 较耗时
4)O_SYNC,O_DSYNC,O_RSYNC:
2.1.3.6 O_DIRECT: 忽略内核缓冲机制, 最小化 I/O 管理, 完全由用户处理请求长度, 缓冲区对齐, 文件偏移是扇区整数倍, 例如数据库系统
2.1.3.7 pwrite: 从指定的偏移量开始写, 不改变当前文件偏移量指针, 可避免竞态的 lseek 调用
- #include <unistd.h>
- ssize_t pwrite(int fd, void *buf, size_t len, off_t pos);
2.1.4 close 系统调用
- #include <unistd.h>
- int close(int fd);
2.1.5 lseek 系统调用
- #include <sys/types.h>
- #include <unistd.h>
- off_t lseek(int fd, off_t pos, int origin);
- origin:SEEK_SET, SEEK_CUR, SEEK_END
pos = 0 时
origin == SEEK_SET: 文件偏移量指向文件起始位置
origin == SEEK_CUR: 返回当前文件偏移量
origin == SEEK_END: 文件偏移量指向文件末尾
2.1.6 truncate & ftruncate 系统调用
截短文件, 成功调用返回文件长度
- #include <sys/types.h>
- #include <unistd.h>
- int ftruncate(int fd, off_t len);
- int truncate(const char *name, off_t len);
2.1.7 select & poll & epoll 系统调用
I/O 多路复用, 若有文件描述符准备好时通知我, 没有就睡眠
2.1.7.1 select
1) 定义
- #include <sys/types.h>
- #include <sys/time.h>
- #include <unistd.h>
- int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
- FD_CLR(int fd, fd_set *set);
- FD_ISSET(int fd, fd_set *set);
- FD_SET(int fd, fd_set *set);
- FD_ZERO(fd_set *set);
2) 参数
n:fd_set 中最大的 fd + 1(不太合理, 导致被 poll 取代)
3) 返回值
成功时返回就绪的文件描述符数目
失败:
EBADF: 某文件描述符非法
EINTR: 等待时捕获了一个信号, 可以重新发起调用
EINVAL: 参数 n 是负数, 或者时间 timeout 不合法
ENOMEM: 没有足够的内存完成请求
4) 示例程序
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/time.h>
- int main()
- {
- struct timeval timeout;
- fd_set set;
- int ret;
- timeout.tv_sec = 3;
- timeout.tv_usec = 0;
- FD_ZERO(&set);
- FD_SET(STDIN_FILENO, &set);
- ret = select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout);
- if(ret <0)
- perror("select");
- else
- {
- if(FD_ISSET(STDIN_FILENO, &set))
- {
- //read
- }
- }
- return 0;
- }
5) 可利用 select 实现 sleep
- 6)pselect
- int pselect(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);
精确到纳秒, 不修改 timeout, 设置阻塞的信号
2.1.7.2 poll
1) 定义
- #include <sys/poll.h>
- struct pollfd
- {
- int fd; // 文件描述符
- short events; // 监视的事件
- short revents; // 发生的事件
- }
- int poll(struct pollfd *fds, unsigned int nfds, int timeout);
2) 事件
- POLLIN,POLLRDNORM,POLLRDBAND,POLLPRI,POLLOUT,POLLWRNORM,POLLBAND,POLLMSG
- 3)ppoll
- int ppoll(struct pollfd *fds, unsigned int nfds, int timeout, const sigset_t *sigmask);
- 2.1.7.3 epoll
解决 select & poll 性能问题, 适合同时监视大量文件描述符, 先初始化, 然后增加, 删除, 最后等待, 分离了三者
1) 定义
- #include <sys/epoll.h>
- int epoll_create(int size);
- int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
- int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
2.2 缓冲文件 I/O
2.2.1 打开文件
- FILE *fopen(const char *name, const char *mode);
- FILE *fdopen(int fd, const char *mode);
2.2.2 关闭文件
- int fclose(FILE *stream);
- int fcloseall();
2.2.3 读文件
2.2.3.1 字节读
- int fgetc(FILE *stream);
- int ungetc(int c, FILE *stream);
2.2.3.2 行读取
int fgets(char *str, int size, FILE *stream): 读取 size-1 个字节至 str 中, 遇到换行符时,'\n'被存入 str 中
2.2.3.3 块读取
int fread(void *buf, size_t size, size_t nr, FILE *stream): 从流 stream 中读入 nr 个元素, 每个元素大小是 size, 返回读入的元素个数
2.2.4 写文件
2.2.4.1 字节写
- int fputc(FILE *stream);
- int unputc(int c, FILE *stream);
2.2.4.2 行写
int fputs(const char *str, FILE *stream);
2.2.4.3 块写
int fwrite(void *buf, size_t size, size_t nr, FILE *stream);
2.2.5 定位文件
int fseek(FILE *stream, long offset, int whence): 移动文件指针到指定位置
int fsetpos(FILE *stream, fpos_t *pos): 跨平台
int fgetpos(FILE *stream, fpos_t *pos)
int ftell(FILE *stream): 返回当前文件位置
int rewind(FILE *stream): 将文件指针置为初始位置
2.2.6 刷新文件
int fflush(FILE *stream): 刷新用户缓冲区数据, 不能刷新内核缓冲区数据
int fileno(FILE *stream): 获取文件描述符 fd, 要先调用 fflush
2.2.7 错误处理
int ferror(FILE *stream): 测试是否有错误
int feof(FILE *stream): 测试是否到达文件末尾
int clearerr(FILE *stream): 清除错误标志
2.2.8 缓冲控制
int setvbuf(FILE *stream, char *buf, int mode, size_t size)
必须在紧邻 fopen 之后调用
mode:_IONBF(无缓冲),_IOLBF(行缓冲),_IOFBF(块缓冲)
2.2.9 文件锁
- int flockfile(FILE *stream);
- int funlockfile(FILE *stream);
- int ftrylockfile(FILE *stream);
以上的流操作函数均是 lock 版, 系统也提供了_unlock 版
2.3 高级文件 I/O
2.3.1 散列聚集 I/O
- #include <sys/uio.h>
- ssize_t readv(int fd, const struct *iov, int count);
- ssize_t writev(int fd, const struct *iov, int count);
单次向量 I/O 代替多次线性 I/O, 降低了系统调用次数, 避免了竞态
2.3.2 直接文件 I/O
1) 定义
- #include <sys/mman.h>
- void *mmap(void *addr, size_t len, int port, int flags, int fd, off_t offset);
- int munmap(void *addr, size_t len);
- void * mremap (void *addr, size_t old_size,size_t new_size, unsigned long flags);
- int mprotect (const void *addr, size_t len, int prot);
- int msync (void *addr, size_t len, int flags);
- int madvise (void *addr, size_t len, int advice);
2)addr: 告诉内核最佳映射地址, 不是强制, 一般置为 0, 调用返回映射地址
3)port: 权限, PORT_READ,PORT_WRITE,PORT_EXEC
4)flags
MAP_FIXED:addr 是强制的
MAP_PRIVATE: 映射区是私有的, 写时拷贝
MAP_SHARED: 映射区是共享的
5) 页对齐: addr 和 len 必须是页对齐的
- long page_size = sysconf(_SC_PAGESIZE); // 最好选择
- int page_size = getpagesize ( );
- int page_size= PAGE_SIZE ;
2.3.3 文件 I/O 提示
- 1)posix fadvise
- #include <fcntl.h>
- int posix_fadvise (int fd, off_t offset, off_t len, int advice);
- 2)readahead
- ssize_t readahead (int fd, off64_t offset, size_t count);
2.3.4 异步文件 I/O
- #include <aio.h>
- /* asynchronous I/O control block */
- struct aiocb
- {
- int aio_filedes; /* file descriptor */
- int aio_lio_opcode; /* operation to perform */
- int aio_reqprio; /* request priority offset */
- volatile void *aio_buf; /* pointer to buffer */
- size_t aio_nbytes; /* length of operation */
- struct sigevent aio_sigevent; /* signal number and value */
- /* internal, private members follow... */
- };
- int aio_read (struct aiocb *aiocbp);
- int aio_write (struct aiocb *aiocbp);
- int aio_error (const struct aiocb *aiocbp);
- int aio_return (struct aiocb *aiocbp);
- int aio_cancel (int fd, struct aiocb *aiocbp);
- int aio_fsync (int op, struct aiocb *aiocbp);
- int aio_suspend (const struct aiocb * const cblist[], int n, const struct timespec *timeout);
Linux 仅仅支持设置了 O_DIRECT 标志的异步操作
2.4 文件属性
2.4.1 inode: 标识一个文件, 在一个文件系统中是唯一的, 既是 linux 内核虚拟对象, 也是外存物理对象
2.4.2 获取文件属性
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
int stat(const char *path, struct stat *buf); 传入文件名
int fstat(int fd, struc stat *buf); 传入文件描述符
int lstat(const char *path, struct stat *buf); 返回链接文件本身
- struct stat {
- dev_t st_dev; /* ID of device containing file */
- ino_t st_ino; /* inode number */
- mode_t st_mode; /* permissions */
- nlink_t st_nlink; /* number of hard links */
- uid_t st_uid; /* user ID of owner */
- gid_t st_gid; /* group ID of owner */
- dev_t st_rdev; /* device ID (if special file) */
- off_t st_size; /* total size in bytes */
- blksize_t st_blksize; /* blocksize for filesystem I/O */
- blkcnt_t st_blocks; /* number of blocks allocated */
- time_t st_atime; /* last access time */
- time_t st_mtime; /* last modification time */
- time_t st_ctime; /* last status change time */
- };
2.4.3 设置文件权限
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- int chmod(const char *path, mode_t mode);
- int fchmod(int fd, mode_t mode);
2.4.4 设置文件所有者
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- int chown(const char *path, uid_t owner, gid_t group);
- int fchown(int fd, uid_t owner, gid_t group);
- int lchown(const char *path, uid_t owner, gid_t group);
2.4.5 扩展属性
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/xattr.h>
1) 命名空间: system,security,trusted,user
2) 获取文件扩展属性
- int getxattr(const char *path, const char *key, void *value, size_t size);
- int fgetxattr(int fd, const char *key, void *value, size_t size);
- int lgetxattr(const char *path, const char *key, void *value, size_t size);
3) 设置文件扩展属性
- int setxattr(const char *path, const char *key, void *value, size_t size, int flags);
- int fsetxattr(int fd, const char *key, void *value, size_t size, int flags);
- int lsetxattr(const char *path, const char *key, void *value, size_t size, int flags);
4) 列举文件扩展属性
- int listxattr(const char *path, char *list, size_t size);
- int flistxattr(int fd, char *list, size_t size);
- int llistxattr(const char *path, char *list, size_t size);
4) 删除文件扩展属性
- int removexattr(const char *path, char *key);
- int fremovexattr(int fd, char *key);
- int lremovexattr(const char *path, char *key);
2.5 目录管理
2.5.1 获取当前目录
- #include <unistd.h>
- char *getcwd(char *buf, size_t size);
2.5.2 更改目录
- #include <unistd.h>
- int chdir(const char *path);
- int fchdir(int fd);
2.5.3 创建目录
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- int mkdir(const char *path, mode_t mode);
2.5.4 删除目录
- #include <unistd.h>
- int rmdir(const char *path);
2.5.5 读取目录
- #include <unistd.h>
- #include <sys/types.h>
- #include <dirent.h>
- DIR *opendir(const char *path);
- struct dirent *readdir(DIR *dir);
- int closedir(DIR *dir);
2.5.5 文件链接
#include <unistd.h>
1) 硬链接
int link(const char *oldpath, const char *newpath);
2) 符号链接
int symlink(const char *oldpath, const char *newpath);
3) 解除链接
int unlink(const char *path);
2.5.6 文件复制移动删除
1) 复制: 无系统级支持, 自己实现
2) 移动
- #include <stdio.h>
- int rename(const char *oldpath, const char *newpath);
3) 删除
- #include <stdio.h>
- int remove(const char *path);
2.6 设备文件
2.6.1 特殊设备文件
1) /dev/null: 空设备, 忽略所有写请求, 读请求返回 EOF
2) /dev/zero: 零设备, 忽略所有写请求, 读请求返回 0
3) /dev/full: 满设备, 写请求返回 ENOSPC, 读请求返回 0
4) /dev/urandom: 随机数生成设备, 优于 / dev/random
2.6.2 设备控制
- #include <stdio.h>
- #include <sys/ioctl.h>
- #include <sys/ioctl.h>
- int ioctl(int fd, int request, ...);
2.7 监视文件
#include <inotify.h>
inotify, 监视文件被创建, 打开, 读取, 写入, 删除等操作
2.7.1 初始化
int inotify_init();
2.7.2 增加监视
int inotify_add_watch(int fd, const char *path, uint32_t mask);
2.7.3 inotify 事件
- struct inotify_event {
- int wd; /* watch descriptor */
- uint32_t mask; /* mask of events */
- uint32_t cookie; /* unique cookie */
- uint32_t len; /* size of 'name' field */
- char name[]; /* null-terminated name */
- };
2.7.4 读取 inotify 事件: read
2.7.5 删除 inotify 事件
int inotify_rm_watch (int fd, uint32_t wd);
2.7.6 退出 inotify:close
三. 进程管理
进程创建 fork 和加载 exec 分离, 是仅次于文件的基本抽象概念
3.1 获取进程 ID
- #include <sys/types.h>
- #include <unistd.h>
- pid_t getpid(void);
- pid_t getppid(void);
1)PID 在某个时刻是唯一的
2) 进程 0:idle 进程, 是所有其他进程的祖先, 在系统初始化时由 kernel 自身从无到有创建.(过程集中在 start_kernel 函数内), 数据成员大部分是静态定义的, 即由预先定义好的 (如上)INIT_TASK, INIT_MM 等宏初始化.
3) 进程 1:init 进程, 由 idle 进程调用 kernel_thread 创建的
3.2 进程创建 fork
- #include <sys/types.h>
- #include <unistd.h>
- pid_t fork(void);
- pid_t pid;
- pid = fork();
- if(pid == -1)
- {
- perror("fork");
- }
- else if(pid == 0)
- {
- // 父进程代码
- }
- else
- {
- // 子进程代码
- if( execlp("gedit", "gedit", "001.txt", NULL) == -1)
- {
- perror("execl");
- exit(EXIT_FAILURE);
- }
- }
3.3 进程加载 exec
#include <unistd.h>
int execl(const char *path, const char *arg, ...): 加载指定路径的程序, 参数列表必须以 NULL 结束
int execlp(const char *path, const char *arg, ...): 在 PATH 环境变量中查找程序
int execle(const char *path, const char *arg, ..., char * const envp[]): 提供给新进程环境变量
- int execv(const char *path, char * const argv[]);
- int execvp(const char *path, char * const argv[]);
- int execve(const char *path, char * const argv[], char * const envp[]);
l 表示以列表方式提供参数, v 表示以数组方式提供参数, p 表示在 PATH 环境变量中查找程序, e 表示提供给新进程环境变量
3.4 进程终止 exit
- #include <stdlib.h>
- void exit(int status);
EXIT_SUCCESS 表示成功, EXIT_FAILURE 表示失败
- 1)_exit
- #include <unistd.h>
- void _exit(int status);
- 2)at_exit
- #include <stdlib.h>
- int at_exit(void (*function)(void ));
3)SIGCHLD: 当进程终止时, 内核会向其父进程发送信号 SIGCHLD
- 4)wait
- #include <sys/types.h>
- #include <sys/wait.h>
- pid_t wait(int *status);
返回已终止子进程 PID, 返回 - 1 表示出错
- 5)waitpid
- #include <sys/types.h>
- #include <sys/wait.h>
- pid_t waitpid (pid_t pid, int *status, int options);
功能更强大
- 6)system
- #include <stdlib.h>
- int systme(const char *command);
创建并等待新进程
- int my_system (const char *cmd)
- {
- int status;
- pid_t pid;
- pid = fork ( );
- if (pid == -1)
- return -1;
- else if (pid == 0) {
- const char *argv[4];
- argv[0] = "sh";
- argv[1] = "-c";
- argv[2] = cmd;
- argv[3] = NULL;
- execv ("/bin/sh", argv);
- exit (-1);
- }
- if (waitpid (pid, &status, 0) == -1)
- return -1;
- else if (WIFEXITED (status))
- return WEXITSTATUS (status);
- return -1;
- }
3.5 进程权限控制
3.5.1 用户 ID
1) 实际用户 ID: 登陆进程使用的 ID
2) 有效用户 ID: 检查进程权限过程中使用的 ID
3) 保存设置用户 ID: 执行 suid 前的有效用户 ID
4) 文件系统用户 ID:
3.5.2 设置用户 ID
- #include <unistd.h>
- #include <sys/types.h>
- int setuid(uid_t uid);
- int setgid(gid_t gid);
- int seteuid(uid_t uid);
- int setegid(gid_t gid);
设置当前进程的有效用户 ID
3.5.3 获取用户 ID
- #include <unistd.h>
- #include <sys/types.h>
- int getuid();
- int getgid();
- int geteuid();
- int getegid();
3.5.4 会话
登陆进程会为新用户创建会话, 会话首进程 (shell)pid 作为会话 ID, 便于作业控制, 可以发信号终止会话首进程的所有子进程
#include <unistd.h>
1) 创建一个会话: pid_t setsid(void);
2) 获取会话 ID: pid_t getsid (pid_t pid);
3) 设置进程组 ID: int setpgid (pid_t pid, pid_t pgid);
3.6 守护进程
- #include <unistd.h>
- int daemon(int nochdir, int noclose);
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <linux/fs.h>
- int main (void)
- {
- pid_t pid;
- int i;
- pid = fork( ); /* create new process */
- if (pid == -1)
- return -1;
- else if (pid != 0)
- exit (EXIT_SUCCESS);
- if (setsid ( ) == -1) /* create new session and process group */
- return -1;
- if (chdir ("/") == -1) /* set the working directory to the root directory */
- return -1;
- for (i = 0; i <NR_OPEN; i++) /* close all open files--NR_OPEN is overkill,but works */
- close (i);
- /* redirect fd's 0,1,2 to /dev/null */
- open ("/dev/null", O_RDWR); /* stdin */
- dup (0); /* stdout */
- dup (0); /* stderror */
- /* do its daemon thing... */
- return 0;
- }
3.7 进程调度
3.7.1 让出处理器
- #include <sched.h>
- int sched_yield(void);
3.7.2 进程优先级
- #include <unistd.h>
- int nice(int inc);
在当前优先级基础上加 inc, 只有拥有 CAP_SYS_NICE 能力才能使用负值 inc 增加优先级, 否则只能降低优先级
- #include <sys/time.h>
- #include <sys/resource.h>
- int getpriority (int which, int who);
- int setpriority (int which, int who, int prio);
3.7.3 处理器亲和度
- #include <sched.h>
- typedef struct cpu_set_t;
- size_t CPU_SETSIZE;
- void CPU_SET (unsigned long cpu, cpu_set_t *set);
- void CPU_CLR (unsigned long cpu, cpu_set_t *set);
- int CPU_ISSET (unsigned long cpu, cpu_set_t *set);
- void CPU_ZERO (cpu_set_t *set);
- int sched_setaffinity (pid_t pid, size_t setsize,const cpu_set_t *set);
- int sched_getaffinity (pid_t pid, size_t setsize,const cpu_set_t *set);
3.7.4 进程调度策略
- #include <sched.h>
- struct sched_param {
- /* ... */
- int sched_priority;
- /* ... */
- };
- int sched_getscheduler (pid_t pid);
- int sched_setscheduler (pid_t pid, int policy,const struct sched_param *sp);
- int sched_getparam (pid_t pid, struct sched_param *sp);
- int sched_setparam (pid_t pid, const struct sched_param *sp);
- int sched_rr_get_interval (pid_t pid, struct timespec *tp);
SCHED_FIFO: 先进先出
SCHED_RR: 轮转
SCHED_OTHER: 普通
3.7.5 资源限制
- #include <sys/time.h>
- #include <sys/resource.h>
- struct rlimit {
- rlim_t rlim_cur; /* soft limit */
- rlim_t rlim_max; /* hard limit */
- };
- int getrlimit (int resource, struct rlimit *rlim);
- int setrlimit (int resource, const struct rlimit *rlim);
- RLIMIT AS,CORE,CPU,DATA,FSIZE,LOCKS,MEMLOCK,MSGQUEUE,NICE,NOFILE,NPROC,RSS,RTPRIO,SIGPENDING,STACK
四. 内存管理
4.1 基本存储 / 释放
- 4.1.1 malloc
- #include <stdlib.h>
- void *malloc(size_t size);
成功会返回指向 size 大小内存区域的首指针, 错误返回 NULL, 设置 errno 为 ENOMEM
- 4.1.2 calloc
- #include <stdlib.h>
- void *calloc(size_t nr, size_t size);
分配数组, 会用 0 初始化
- void *xmalloc0(size_t size)
- {
- void *p = NULL;
- p = calloc(1, size);
- if(p == NULL)
- {
- perror("malloc");
- exit(EXIT_FAILURE);
- }
- return p;
- }
- 4.1.3 realloc
- #include <stdlib.h>
- void *realloc(void *ptr, size_t size);
重新分配, 可改变已分配内存区域的大小, 主要用途是变小
- 4.1.4 free
- #include <stdlib.h>
- void free(void *ptr);
ptr 必须是 malloc/calloc/realloc 的返回值
4.2 字节对齐
- #include <stdlib.h>
- int posix_memalign (void **memptr,size_t alignment,size_t size);
成功时返回 size 字节的动态内存, 且以 alignment,alignment 必须是 2 的幂
4.3 匿名映射
- void *p;
- p = mmap (NULL, 512 * 1024, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- if (p == MAP_FAILED)
- perror ("mmap");
- else
- /* p points at 512 KB of anonymous memory... */
- ...
- int ret;
- ret = munmap(p, 512 * 1024);
- if(ret)
- perror("munmap");
适合大内存区域分配
4.4 设置内存分配参数
- #include <malloc.h>
- int mallopt (int param, int value);
- size_t malloc_usable_size (void *ptr);
- int malloc_trim (size_t padding);
4.5 调试内存分配
- #include <malloc.h>
- struct mallinfo mallinfo (void);
- /* all sizes in bytes */
- struct mallinfo {
- int arena;
- int ordblks;
- int smblks;
- int hblks;
- int hblkhd;
- int usmblks;
- int fsmblks;
- int uordblks;
- int fordblks;
- int keepcost;
- };
- #include <malloc.h>
- void malloc_stats (void);
4.6 栈分配 & 变长数组
- #include <alloca.h>
- void * alloca (size_t size);
来源: http://www.bubuko.com/infodetail-2729663.html