1.open()函数
#include <sys/file.h>
(1)函数名:
open
(2)头文件:
<io.h>
(3)函数原型:
int open(char *pathname,int oflag,[,int auth]);
(4)参数:
(1)pathname:待打开/创建文件的路径名(如 C:/cpp/a.cpp);
(2)oflag:是打开/创建文件的模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成.
(3)auth:仅当创建新文件时(即 使用了O_CREAT 时)才使用,用于指定文件的访问权限位(access permission bits).
(5)注解:
oflag 用于指定文件的打开/创建模式,这个参数可由以下常量(定义于 fcntl.h)通过逻辑或构成
打开/创建文件时,至少得使用以下三个常量中的一个
O_RDONLY 只读模式
O_WRONLY 只写模式
O_RDWR 读写模式
以下常量是选用的:
O_APPEND 每次写操作都写入文件的末尾
O_CREAT 如果指定文件不存在,则创建这个文件
O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改 errno 的值
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容(即将其长度截短为0)
O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O
#include <stdio.h>
#include<io.h>
#include<fcntl.h>
int main()
{
int fd;
char buf[100];
fd=open("test.txt",O_RDWR);
if(fd==-1)
{
printf("open error\n");
return -1;
}
read(fd,buf,100);
printf("%s\n",buf);
close(fd);
return 0;
}
2.flock() 函数
多进程之间的通信以及资源共享,多进程之间文件共享冲突
exp:
写进程-------->数据文件--------->读进程
多进程读写文件冲突
与常规的多进程读写冲突是有区别的:
传统的多进程是统一服务中通过fork派生出来的多进程,读写冲突通常是对内存中的数据结构进行读写。
该数据文件更新场景下的多进程,产生冲突的操作对象是文件,而且这里的进程可能是独立的无任何关系的进程。
文件🔓flock
flock -apply or remove an advisory lock on an open file
(1)advisory lock
(2)open file
共享锁与互斥锁
linux中flock系统调用的原型:
#include <sys/file.h>
int flock (int fd ,int operation);
当flock执行成功,返回0,当出现错误,返回-1,并设置相应的errno
operation:使用LOCK_SH 或者LOCK_EX常量,分别对应共享锁和排他锁。
LOCK_SH:共享锁,允许多个进程同时访问文件,但只有一个进程可以修改文件。(读锁)
LOCK_EX:排他锁,允许一个进程修改文件,但其他进程不能访问。(写锁)
LOCK_NB:非阻塞锁,如果文件已经被锁定,则立即返回。
LOCK_UN:解锁,释放文件锁。
3.fork()函数
用于创建一个进程,所创建的进程赋值父进程的代码段/数据段/BSS段/堆栈/等所有的用户空间信息,在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化
(1)fork()函数的原型
pid_t fork(void);//pid_t为int类型进行了重载
pid_t getpid();//获取当前进程的进程号
pid_t getppid();//获取当前进程的父进程的pid
/*
* 主函数
* 无参数
* 返回值:程序执行结果,0表示成功,非0表示失败
*/
int main()
{
pid_t fpid; // 存储fork函数返回值的变量
int count = 0; // 用于计数的变量
// 创建一个新的进程
fpid = fork();
// 判断fork函数调用是否成功
if(fpid < 0)
{
printf("fork error\n"); // fork函数调用失败,打印错误信息
return -1; // 返回错误码
}
else if (fpid == 0)
{
// 这里是子进程的代码段
printf("child process pid = %d, ppid = %d\n", getpid(), getppid()); // 打印子进程的PID和父进程的PID
printf("子进程\n");
count++; // 子进程计数加一
}
else
{
// 这里是父进程的代码段
printf("parent process pid = %d, ppid = %d\n", getpid(), getppid()); // 打印父进程的PID和父进程的父进程的PID
printf("父进程\n");
count++; // 父进程计数加一
}
// 打印计数结果
printf("统计结果是:%d\n",count);
return 0; // 程序执行成功,返回0
}
(2)fork()函数的特性
它仅仅被调用一次,却能够返回两次,有三种不同的返回值:
1.在父进程中,fork返回新创建子进程的进程ID
2.在子进程中,fork返回0
3.如果出现错误,fork返回-1
exp:
A进程父进程 B进程是子进程
A进程
pid = fork();
pid == "子进程的进程ID"
B进程
pid = fork();
pid == 0;
因此我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
(注: fork 调用生成的新进程与其父进程谁先执行不一定,哪个进程先执行要看系统的进程调度策略)
fpid的值(fork()的值)为何在父子进程中不同
相当于链表:进程形成了链表,父进程的fpid(p相当于point)指向子进程。子进程没得指。
(3)fork()函数的执行过程
(1)申请pid
(2)申请PCB结构
(3)复制父进程的PCB
(4)将子进程的运行状态设置为不可执行的
(5)将子进程的某些属性清零,某些保留,某些修改
(6)复制父进程的页