*系统编程**
一、文件描述符
(一)open打开文件
int open(const char *pathname, int flags);
参数:
@pathname 路径
@flags 标志位
O_RDONLY :表示只读
O_WRONLY :表示只写
O_RDWR :表示可读可写
O_CREAT :表示创建
O_TRUNC :表示清空
O_APPEND :表示追加
O_NONBLOCK :表示取消阻塞
r : O_RDONLY
r+ : O_RDWR
w : O_CREAT | O_TRUNC | O_WRONLY
w+ : O_RDWR | O_CREAT | O_TRUNC
a : O_APPEND | O_CREAT | O_WRONLY
a+ : O_APPEND | O_CREAT | O_RDWR
retrun:
成功:未使用最小文件描述符
0 标准输入 stdin
1 标准输出 stdout
2 错误输出 stderr
失败:-1
(二)close关闭文件
int close(int flags);
参数:
@flags 要关闭的文件描述符
(三)read读文件
ssize_t read(int fd, void *buf, size_t count);
参数:
@fd 文件描述符
@buf 存储数据空间地址
@count 要读的多少字节
返回值:
成功:读到的字符个数
失败:-1
(四)write写文件
ssize_t write(int fd, const void *buf, size_t count);
参数:
@fd 文件描述符
@buf 存储数据空间地址
@count 要写的多少字节
返回值:
成功:写入的字符个数
失败:-1
(五)lseek指针偏移
off_t lseek(int fildes, off_t offset, int whence);
参数:
@fildes 文件描述符
@offser 偏移量
@whence 相对位置
SEEK_SET(开头)
SEEK_CUR(当前)
SEEK_END
返回值:
成功:偏移大小(文件开头)
失败:-1
二、其他一些命令
(一)共享文件描述符
(一)dup
int dup(int oldfd);
参数:
@oldfd 文件描述符
返回值:
成功:未使用最小共享文件描述符
失败:-1
(二)dup2
int dup2(int oldfd, int newfd);
参数:
@oldfd 旧文件描述符
@newfd 新文件描述符
返回值:
成功:指定使用的最小文件描述符
失败:-1
如果指定正在使用的文件描述符,则会把使用的文件描述符关闭掉,然后在指向旧的文件描述符。
(二)执行外部命令exec
(一)execl
int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
参数:
@path 命令路径(绝对路径)
@arg0 命令名
@... 命令的参数
(char *)0 : 表示命令参数结束标记
return:
成功:0
失败:-1
三、进程编程
(一)创建进程
pid_t fork(void);
返回值:
-1 : 失败
0 : 子进程
child_pid : 父进程
pid_t vfork(void);
1 不可以使用return , 则会导致段错误
2 vfork()创建子进程,可以确保子进程先运行
3 vfork创建的内存空间是共享的
(二)进程等待
pid_t wait(int *status);
参数:
@status 等待子进程退出状态
不关心子进程状态 NULL
返回值:
成功:返回等待进程的进程号
失败:-1
父进程等待子进程,只能等待任意一个子进程
四、进程间的通信
(一)信号
软中断机制,并不是正确发送数据
(一)信号源:kill -l
2) SIGINT : ctrl + c
3) SIGQUIT : ctrl + \
6) SIGABRT : abort
9) SIGKILL : 杀死信号
13) SIGPIPE :管道异常信号
14)SIGALRM :闹钟信号
(二)发送信号
int kill(pid_t pid, int sig);
参数:
@pid 进程号
@sig 信号值
return:
成功:
失败:-1
(三)捕捉信号
sighandler_t signal(int signum, sighandler_t handler);
参数:
@signum 捕捉信号值
@handler 捕捉到信号执行操作
SIG_DFL : 表示终止
SIG_IGN : 表示忽略
sighandler_t : 表示自定义
typedef void (*sighandler_t)(int);
返回值:
失败: SIG_ERR
成功:!SIG_ERR
(二)管道
(一)基本概念
管道:异步通知 半双工模式
匿名管道:通过管道标识来通讯
只能实现父子进程或者兄弟进程之间通讯。
有名管道:就是通过管道文件通讯
可以实现任意进程之间通讯
数据通讯的三种方式:
1 单工:这根管道只能发送数据或者说只能接受数据
2 半双工:这根管道一端只能接受数据而另一端只能发送数据
3 全双工:这根管道一端即可以发送数据也可以接受数据
(二)匿名管道
int pipe(int filedes[2]);
参数:
@filedes 数组
filedes[0] is for reading
filedes[1] is for writing
返回值:
成功:0
失败:-1
(三)有名管道
int mkfifo(const char *pathname, mode_t mode);
参数:
@pathname 文件路径
@mode 文件权限
返回值:
成功:0
失败:-1
(四)文件存在
int access(const char *pathname, int mode);
参数:
@pathname 路径
@mode 模式
R_OK: 是否有读的权限
W_OK: 写
X_OK: 可执行
F_OK: 判断文件是否存在
返回值:
成功:0
失败:-1
(三)消息队列(IPC)
(零)获取key
key_t ftok(const char *pathname, int proj_id);
参数:
@pathname 路径
@proj_id 用户指定的序号
return:
成功:key
失败:-1
(一)创建消息队列
int msgget(key_t key, int msgflg);
参数:
@key 关键字
@msgflg 标志位
IPC_CREAT 创建消息队列
IPC_EXCL 判断消息队列是否存在,与IPC_CREAT配合 使用
return:
成功:消息队列id
失败:-1
(二)发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz,int msgflg);
参数:
@msgid 消息队列id
@msgp 发送消息空间地址
@msgsz 消息大小
@msgflg 标志位 0
IPC_NOWAIT :表示是否阻塞
返回值:
失败:-1
成功:0
(三)接收信息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
参数:
@msgid 消息队列id
@msgp 存储数据空间地址
@msgsz 空间大小
@msgtyp 数据类型
不考虑数据类型 :0
@msgflg 标识位 0
return:
失败:-1
成功:接受字符个数
(四)销毁消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
参数:
@msgid 消息队列id
@buf 执行指令
IPC_STAT : 表示获取消息队列属性
IPC_SET : 表示修改消息队列属性
IPC_RMID : 表示销毁消息队列
.....
返回值:
成功:...
失败:-1
(四)共享内存(IPC)
(一)创建共享内存
int shmget(key_t key, size_t size, int shmflg);
参数:
@key 关键字
@size 共享内存大小
@shmflg 标志位
IPC_CREAT
返回值:
成功:返回共享内存id
失败:-1
(二)共享内存映射
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
@shmid 共享内存id
@shmaddr 映射空间地址
NULL : 系统自动分配一个可以操作地址空间
@shmflg 标志位
0 : 可读可写
返回值:
失败:NULL
成功:表示系统允许操作的空间地址
(三)解除共享映射
int shmdt(const void *shmaddr);
参数:
@shmaddr 映射内存地址
return:
成功:0
失败:-1
(四)销毁共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
参数:
@shmid 共享内存id
@cmd
IPC_RMID : 销毁指令
@buf
return:
成功:
失败:-1
(五)信号量(IPC)
(一)创建信号量锁
int semget(key_t key, int nsems, int semflg);
参数:
@key 关键字
@nsems 锁的个数
@semflg 标志位
IPC_CREAT
返回值:
失败:-1
成功:表示信号量锁的id
(二)初始化信号锁
int semctl(int semid, int semnum, int cmd, ...);
参数:
@semid 锁的id
@semnum 锁的索引号
锁的索引号是从0开始,依次类推
@cmd 对锁执行命令
IPC_STAT : 表示锁属性
IPC_SET : 表示设置锁属性
IPC_RMID : 表示锁的销毁
SETVAL : 表示某一把锁
锁的状态必须是打开状态
@... 对命令补充
返回值:
成功:0
失败:-1
(三)加锁和解锁
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数:
@semid 信号量锁id
@sops 信号量锁信息结构体
unsigned short sem_num; 锁的索引号
short sem_op; 正数:解锁,负数:加锁
short sem_flg; 锁的标志:0互斥锁
@nsops 锁的个数
返回值:
成功:0
失败:-1
五、线程
(一)基本概念
线程:
一段可执行程序,并且在内存中运行
识别线程的唯一标识是线程号
属性:
进程独享内存空间,而线程是共享内存空间
关系:
一个程序,至少包括一个进程,而一个进程至少包括一个线程。
进程是资源管理的最小单位
线程是执行流的最小单位
进程包括线程,而不是线程包括进程
区别?
1 线程的执行效率比进程要高,因为进程独享内存空间,而线程是共享内存空间,所以进程之间切换需要时间上开销,而线程切换不需要时间上开销。
2 进程在保护模式下异常退出,另一个进程不受影响。但是同一进程的线程出现异常,则导致整个进程的所有线程出现异常。
(二)获取线程号
pthread_t pthread_self(void);
注意:
1 线程号类型
%lu
2 线程属于第三方库
-l pthread
(三)创建线程
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
参数:
@restrict rhread 存储创建线程的线程号
@restrict attr 线程属性
一般为NULL
@start_routine 线程执行函数
NULL : 表示线程创建成功后不执行
@restrict arg 线程执行函数参数
NULL : 表示不给线程执行函数传递参数
返回值:
成功:0
失败:!0
(四)线程退出
void pthread_exit(void *value_ptr);
参数:
线程返回地址
NULL
(五)线程等待
int pthread_join(pthread_t thread, void **value_ptr);
参数:
@thread 等待线程的线程号
@value_ptr 等待线程返回值
NULL : 不接受返回值
返回值:
(六)线程互斥锁
动态锁:
1 初始化锁
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
参数:
@nutex 锁变量
@restrict attr 锁属性
NULL
2 锁销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:
@mutex 锁变量
3 设置加锁和解锁
表示加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);
表示解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
尝试 加锁
int pthread_mutex_trylock(pthread_mutex_t *mutex);
静态锁:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
不用初始化和销毁锁,直接加锁解锁
(七)线程清理
注册函数
void pthread_cleanup_push(void (*routine)(void*),void *arg);
参数:
@routine 函数指针
@arg 清理函数参数
清理执行函数
void pthread_cleanup_pop(int execute);
参数:
@execute 是否执行清理函数
!0 执行清理函数
0 不执行清理函数
注意:
1 代码执行跟代码所在的位置有关
2 注册函数和清理函数要一一对应
3 注册函数和清理函数是相反的 先进后出