文件操作
open close
打开、关闭文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <fcntl.h> #include <unistd.h> int open(const char *pathname, int flags);
int fd = open("example.txt", O_RDONLY); int close(int fd);
|
read write
读写文件
1 2 3
| #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count);
|
lseek
移动文件内指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 标准C库的函数 #include <stdio.h> int fseek(FILE *stream, long offset, int whence);
Linux系统函数 #include <sys/types.h> #include <unistd.h> off_t lseek(int fd, off_t offset, int whence);
|
stat
获取文件的元数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <sys/stat.h> #include <unistd.h>
int stat(const char *pathname, struct stat *statbuf); int lstat(const char *pathname, struct stat *statbuf);
struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; blksize_t st_blksize; blkcnt_t st_blocks; };
|
st_mode
中的文件类型可以通过以下宏检查:
- 文件类型:
S_ISREG(st_mode)
:常规文件。
S_ISDIR(st_mode)
:目录。
S_ISLNK(st_mode)
:符号链接。
S_ISCHR(st_mode)
:字符设备。
S_ISBLK(st_mode)
:块设备。
S_ISFIFO(st_mode)
:FIFO/管道。
S_ISSOCK(st_mode)
:套接字。
- 文件权限:
st_mode & S_IRUSR
:用户可读。
st_mode & S_IWUSR
:用户可写。
st_mode & S_IXUSR
:用户可执行。
文件属性操作函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| int access(const char *pathname, int mode);
int chmod(const char *filename, int mode);
int chown(const char *path, uid_t owner, gid_t group);
int truncate(const char *path, off_t length);
|
目录操作函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| int rename(const char *oldpath, const char *newpath);
int chdir(const char *path);
char *getcwd(char *buf, size_t size);
int mkdir(const char *pathname, mode_t mode);
int rmdir(const char *pathname);
|
目录遍历函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| DIR *opendir(const char *name);
struct dirent *readdir(DIR *dirp);
int closedir(DIR *dirp);
struct dirent { ino_t d_ino; off_t d_off; unsigned short int d_reclen; unsigned char d_type; char d_name[256]; };
|
dup dup2
1 2 3 4
| int dup(int oldfd);
int dup2(int oldfd, int newfd);
|
Linux多进程
管道
mkfifo
是一个用于创建命名管道(FIFO,First In First Out)的系统调用。命名管道用于在不同进程之间进行通信。
1 2 3 4
| int mkfifo(const char *pathname, mode_t mode);
|
内存映射
这两个函数用于在文件映射/匿名映射区开辟内存
重要:见内存映射注意事项.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
|
信号
通用信号发送函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <signal.h>
int kill(pid_t pid, int sig);
int raise(int sig);
void abort(void);
|
定时器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| #include <unistd.h> unsigned int alarm(unsigned int seconds);
int setitimer(int which, const struct itimerval *new_val, struct itimerval *old_value);
|
信号捕捉
注意:SIGKILL SIGSTOP不能被捕捉,不能被忽略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| sighandler_t signal(int signum, sighandler_t handler);
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
|
信号集
这些函数用于操作和管理信号集(sigset_t),常用于信号处理的信号屏蔽和管理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
int sigpending(sigset_t *set);
|
SIGCHLD 信号产生条件
SIGCHLD信号产生的3个条件:
1.子进程结束
2.子进程暂停了
3.子进程继续运行
都会给父进程发送该信号,父进程默认忽略该信号。
共享内存
头文件
#include <sys/ipc.h>
此头文件定义了与 System V IPC(进程间通信) 相关的常量和数据结构。主要功能包括:
- 定义键值类型和标志:
key_t
:共享内存、消息队列或信号量的键值类型。
IPC_CREAT
:如果指定键的 IPC 对象不存在,则创建一个新的对象。
IPC_EXCL
:与 IPC_CREAT
一起使用,确保指定键的 IPC 对象不存在,否则操作失败。
IPC_PRIVATE
:创建一个仅供调用进程使用的新 IPC 对象。
- 通用命令(用于控制 IPC 对象):
IPC_RMID
:删除 IPC 对象。
IPC_SET
:设置 IPC 对象的权限。
IPC_STAT
:获取 IPC 对象的状态信息。
#include <sys/shm.h>
此头文件定义了与 System V 共享内存 相关的常量、数据结构和函数。主要内容包括:
- 共享内存标识符和标志:
shmget()
:创建或访问一个共享内存段。
shmat()
:将共享内存附加到调用进程的地址空间。
shmdt()
:将共享内存从调用进程的地址空间分离。
shmctl()
:控制共享内存段(例如删除或查询状态)。
- 常量定义:
SHM_RDONLY
:共享内存以只读方式附加。
SHM_R
和 SHM_W
:读取和写入共享内存的权限。
- 数据结构:
struct shmid_ds
:存储共享内存段的元数据,例如大小、权限和使用情况。
实际实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| #include <sys/ipc.h> #include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
int shmid = shmget(key, 1024, 0666 | IPC_CREAT | IPC_EXCL);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
struct shmid_ds { struct ipc_perm shm_perm; size_t shm_segsz; time_t shm_atime; time_t shm_dtime; time_t shm_ctime; pid_t shm_cpid; pid_t shm_lpid; shmatt_t shm_nattch; }; struct ipc_perm { uid_t uid; gid_t gid; mode_t mode; };
key_t ftok(const char *pathname, int proj_id);
|
共享内存操作命令
1 2 3 4 5
| # 查看进程间通信资源信息 ipcs -a # 打印当前系统中所有的进程间通信方式的信息 ipcs -m # 打印使用共享内存进行进程间通信的信息 ipcs -q # 打印使用消息队列进行进程间通信的信息 ipcs -s # 打印使用信号进行进程间通信的信息
|
1 2 3 4 5 6 7
| # 删除进程间通信资源 ipcrm -M shmkey # 移除用 shmkey 创建的共享内存段 ipcrm -m shmid # 移除用 shmid 标识的共享内存段 ipcrm -Q msgkey # 移除用 msgkey 创建的消息队列 ipcrm -q msqid # 移除用 msqid 标识的消息队列 ipcrm -S semkey # 移除用 semkey 创建的信号 ipcrm -s semid # 移除用 semid 标识的信号
|
操作系统如何知道一块共享内存被多少个进程关联?
- 操作系统通过
struct shmid_ds
结构体中的 shm_nattch
成员来记录关联的进程数量。
可以对共享内存进行多次删除吗?
- 可以。
shmctl
标记共享内存为删除状态,但不会立即删除。只有当与共享内存关联的进程数为 0 时,内核才会实际删除它。
共享内存与内存映射的区别
特性 |
共享内存 |
内存映射 |
创建方式 |
直接创建共享内存 |
需要磁盘文件(除非是匿名映射) |
效率 |
更高 |
较低 |
内存访问 |
所有进程访问同一块共享内存 |
每个进程在自己的虚拟地址空间中有独立的内存 |
数据安全 |
进程退出共享内存仍存在 |
进程退出,内存映射区数据消失 |
|
系统宕机时,数据丢失 |
系统宕机时,内存映射区数据仍保存在磁盘文件中 |
生命周期 |
进程退出共享内存依然存在 |
进程退出,内存映射区销毁 |
|
进程退出自动取消关联,关机时可销毁 |
通过标记删除或关机删除内存映射区 |
Linux多线程
线程管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
pthread_t pthread_self(void);
int pthread_equal(pthread_t t1, pthread_t t2);
void pthread_exit(void *retval);
int pthread_join(pthread_t thread, void **retval);
int pthread_detach(pthread_t thread);
int pthread_cancel(pthread_t thread);
|
线程属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| pthread_attr_t
typedef struct pthread_attr { int detachstate; size_t stacksize; void *stackaddr; int schedpolicy; int schedparam; int inheritsched; int guardsize; } pthread_attr_t;
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
|
互斥量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| pthread_mutex_t mutex;
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
读写锁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <stdio.h> #include <pthread.h> #include <unistd.h>
pthread_rwlock_t rwlock;
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
|
条件变量
条件变量的条件指的是被cond
所阻塞的线程需要等待的一个相应通知,而不是某个逻辑表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| pthread_cond_t cond;
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
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);
struct timespec { time_t tv_sec; long tv_nsec; };
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
|
信号量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| sem_t sem;
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
int sem_post(sem_t *sem);
|
v1.4.18