目录结构
1 底层系统调用
2 标准IO库
3 格式化输入输出
4 带缓冲的IO和不带缓冲的IO
5 目录操作
6 文件和目录的维护
7 proc文件系统
8 锁文件
9 文件锁
想必在此之前,你已经听说过这么一句话,在linux中,一切(几乎一切)都是文件,设置硬件设备也被映射为文件,Linux中比较重要的设备文件有3个:
/dev/console:系统控制台
/dev/tty:终端控制,由系统自动运行的进程和脚本没有控制终端,所以它们不能打开/dev/tty
/dev/null:空设备,在cp命令里把它用作复制空文件的源文件,例如:
cp /dev/null empty_file
一 底层系统调用
文件操作的底层系统调用常用的有以下几个:
open | 打开文件或设备 |
read | 从打开的文件或者设备里面读数据 |
write | 向文件或设备里写数据 |
close | 关闭文件或设备 |
lseek | 设置读写指针 |
fstat/stat/lstat | 获取文件相关信息 |
mmap/msync | 内存映射 |
当一个进程(process)开始运行时,一般会有3个已经打开的文件描述符:
0 | 标准输入 |
1 | 标准输出 |
2 | 标准错误 |
open
int open(const char *path,int oflags);
int open(const char *path,int oflags,mode_t mode);
— 参数解释 —
- path:文件路径和文件名
- oflags:
O_RDONLY:以只读方式打开
O_WRONLY:以只写方式打开
O_RDWR:以读写方式打开
可选的组合模式:
O_APPEND:把写入的数据追加在文件的末尾
O_TRUNC:把文件的长度设置为0,丢弃已有的内容
O_CREAT:如果需要,则创建文件,比较常用
O_EXCL:与O_CREAT一起使用,使用这个模式可以方式两个进程同时创建出一个文件,如果文件已经存在,则创建失败。
- mode:
如果你使用O_CREAT标志的open来创建文件时,你必须使用三个参数的open函数。
第三个参数是文件的读/写/执行权限,一般是以0开头的三个八进制数,每个八进制数都是由1/2/4中的一个或几个进行相加得到的。
这三个八进制中,第一个表述属主的权限,第二个表示组的权限,第三个表示其他用户的权限。
0 | 允许任何权限 |
1 | 禁止执行权限 |
2 | 禁止写权限 |
4 | 禁止执行权限 |
- 返回值:
open调用成功时会返回一个新的文件描述符(非负整数),在失败时返回-1。
值得注意的是,返回的新的文件描述符总是未使用描述符的最小值,这个特征非常有用,后面的文章会提到。
read
size_t read(int fildes,void *buf,size_t nbytes);
—参数解释—
- filedes: 文件描述符
- buf: 存放数据的缓冲区
- nbytes: 读取的字节数
- 返回值:返回实际读取的字节数,这可能会小于请求的字节数。如果返回的是0,表示已经到达文件尾,未读入任何数据,如果返回的是-1,表示read调用出现了错误。
write
size_t write(int fildes,const void *buf,size_t nbytes);
—参数解释—
- filedes: 文件描述符
- buf: 要写入的缓冲区
- nbytes: 准备写入的字节数,写入的是缓冲区的前nbytes个字节
- 返回值:返回实际写入的字节数,可能会小于nbytes,如果返回0,表示未写入任何数据,返回-1,表示发生错误。
close
int close(int fildes);
- 终止文件描述符与其对应的文件之间的关系
- 释放文件描述符并使其能够重新使用
- 成功返回0,失败返回-1
lseek
lseek用于对文件描述符fildes的读写指针进行设置。
off_t lseek(int fileds,off_t offset,int whence);
—参数解释—
- off_t offset:off_t是一个整数类型,offset表示偏移值
- whence
SEEK_SET | offset是一个绝对位置 |
SEEK_CUR | offset是一个相对于当前位置的相对位置 |
SEEK_END | offset是一个相对于文件尾的相对位置 |
- 返回值
返回从文件头到文件指针的字节偏移值,失败时返回-1.
fstat/stat/lstat
int fstat(int fildes,struct stat *buf);
int stat(const char *path,struct stat *buf);
int lstat(const char *path,struct stat *buf);
- fstat 通过文件描述符返回相关的文件状态信息
- stat/lstat 是通过文件名查到文件的状态信息
- stat/lstat的区别:当查到的文件名是一个符号链接时,lstat返回的是该符号链接本身的信息,stat返回的是该链接指向的文件的信息。
mmap/msync
void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);
函数功能
- mmap函数创建一段指向内存区域的指针,该内存区域与可以通过一个文件描述符访问的文件的内容相关联。
- 简单的说,就是把二进制文件的内容放在内存里,读写文件就可以使用指针操作,方便对某个字节进行读写操作。
函数参数
- addr : 分配的内存地址,一般设置为NULL,即由系统进行分配
- len : 需要分配的长度
- prot: 设置内存访问的权限,有PORT_READ读/PORT_WRITE写/PORE_EXEC执行,按位OR操作
- fildes : 已经打开的文件描述符
- off:内存访问的文件中数据的起始偏移地址
int msync(void *addr,size_t len,int flags);
函数功能:把映射的内存段写回到被映射的文件中
- flasgs:执行修改的具体方式
MS_ASYNC | 采用异步写方式 |
MS_SYNC | 采用同步写方式 |
MS_INVALIDATE | 从文件中读回数据 |
二 标准IO库
IO标准库提供的读写函数主要有以下几个
fopen | 打开文件 |
fread | 读取文件数据 |
fwrite | 向文件写数据 |
flose | 关闭文件流 |
fflush | 写出缓冲区中所有的数据 |
fseek | 移动读写指针 |
fgetc/getc/getchar | 从文件流中获取一个字节 |
fputc/putc/putchar | 输出一个字节到文件流中 |
fgets/gets | 从文件流中获取字符串 |
标注IO库stdio为底层I/O系统调用提供了一个通用的接口,还提供了许多复杂的函数用于格式化输出和扫面输入,它还负责满足设备的缓冲需求。
在标准IO库中,与文件描述符对应的是流(stream),它是指向结构FILE的指针。
同样,在启动程序时,由3个流时自动打开的,分别是
stdin | 标准输入 |
stdout | 标准输出 |
stderr | 标准错误 |
fopen
FILE *fopen(const char *filename,const char *mode);
— 参数解释 —
- filename:指定的文件
- moed:指定的打开方式
"r" / "rb" :只读
"w" / "wb" : 只写,把文件长度截短为零
"a" / "ab" : 只写,新内容追加在文件尾
"r+"/"rb+"/"r+b" : 以更新方式打开,读/写
"w+"/"wb+"/"w+b" : 以更新方式打开,并把文件长度截短为0
"a+"/"ab+"/"a+b" : 以更新方式打开,新内容追加在文件尾
- 返回值:
成功返回一个非空的FILE * 指针
失败返回NULL
fread
size_t fread(void *ptr,size_t size,size_t nitems,FILE *stream);
—参数解释—
- ptr : 数据存放的缓冲区
- size: 每次读取的长度
- nitems: 读取的次数
- stream:文件流
- 返回值:放到缓冲区里面的数据块的个数,而不是字节数
fwrite
size_t fwrite(const void *ptr,size_t size,size_t nitems,FILE *stream);
—参数解释—
- ptr : 数据存放的缓冲区
- size: 每次写入的长度
- nitems: 写入的次数
- stream:文件流
- 返回值:写入的个数
flose
int fclose(FILE *stream);
- flose关闭文件流stream,使所有尚未写出的数据都写出,因为stdio会对数据进行缓冲,所以使用fclose是非常重要的。
fflush
int fflush(FILE *stream);
- 把文件流里面所有未写出的数据立刻写出,可以用这个函数来确保在试图读入一个用户响应之前,先向终端送出一个交互提示符。
- flose()隐含执行了一次fflush函数
fseek
int fseek(FILE *stream,long int offset,int whence);
offset和whence的含义与lseek一样,不一样的时fseek返回的是一个整数,0表示成功,-1表示失败。
fgetc/getc/getchar
int fgetc(FILE stream);
int getc(FILE *stream);
int getchar();
- fgetc从文件流里面取出下一个字节并把它作为字符返回,当到达文件尾部或者发生错误时返回EOF.
- getc与fgetc的作用一样,但是它有可能被声明成一个宏(被ISO C声明为一个宏),所以它不可以作为函数指针,宏会需要更多的内存空间,但是有更高的执行效率。
- getchar的作用相当于getc(stdin),从标准里读取下一个字符
fputc/putc/putchar
int fputc(int c,FILE *stream);
int putc(int c,FILE *stream);
int putchar(int c);
类似于fgetc/fget/getchar
之间的关系
注意,putchar和getchar都是把字符当作int类型而不是char类型来使用的,这就允许文件尾(EOF)标识取值-1
fgets/gets
char *fgets(char *s,int n,FILE *stream);
char *gets(char *s);
- fgets把读到的字符写到S所指向的字符串里,直到遇到换行符或者文件尾,也会把换行符接受到字符串里,并加上结尾字符\0,一次调用最多传输n-1个字符,因为最后一个字符必须是\0
成功时,返回指向s的指针,失败时,返回一个空指针 - gets类似于fgets,只不过它是从标准输入读取数据并丢弃换行符,并在结尾加上null字符
三 格式化输入输出
1 标准输出函数
printf/fprintf/sprintf
int printf(const char *format,...);
int sprintf(char *s,const char *format,...);
int fprintf(FILE *stream,const char *format,...);
- printf 把自己的输出送到标准输出
- fprintf 把自己的输出送到一个指定的文件流##
- sprintf 把自己的输出和一个结尾空字符写到字符串s里面
scanf/fscanf/sscanf
int scanf(const char *format,...);
int fscanf(FILE *stream,const char *format,..);
int sscanf(const char *s,const char *format,...);
- scanf 读入标准输入的值保存到对应的变量里去,这些变量的类型必须正确并且精确匹配格式字符串,斗则,内存数据会遭到破坏,使程序崩溃
使用%c控制符从输入中读取一个自读,它不会跳过起始的空白字符
使用%s控制符来扫描字符串,它会跳过起始的空白字符
返回值是成功读取的数据项个数
例:
给定下面的输入行:
hello, 1234, 5.678, X, string to the end of the line
下面的scanf会正确读取4个数据项:
char s[256];
int n;
float f;
char c;
scanf("Hello,%d,%g, %c, %[^\n]",&n,&f,&c,s);
/*
* 1 注意%c前面有空格,是为了匹配字符X之前的空格
* 2 %[^\n]: 表示遇到\n停止读取字符串
*/
- fscanf 从文件流读取数据到对应项中
- sscanf 从字符串读取数据到对应项中
四 带缓冲的IO与不带缓冲的IO
底层系统调用提供的IO读写操作是不带缓存的IO
标准库stdio提供的IO读写操作是带缓存的IO
看下面两个函数
size_t write(int fildes,const void *buf,size_t nbytes);
size_t fwrite(const void *ptr,size_t size,size_t nitems,FILE *stream);
在数据读入buff或者是ptr之前,都会先写到内核所设置的缓冲存储器中。如果存储器未满,则并不将其排入到输出队列,直到缓存写满或者内核需要重新使用此缓存时才将其排入输出队列,再进行实际的IO操作,这种技术叫延迟写
标准IO在系统调用上多加了一个缓冲区,也因此引入了流的概念,FILE实际上包含了管理流所需要的所有信息:
- 实际的IO文件描述符
- 指向流缓存的指针
- 缓存长度
- 当前在缓存中的字节数
标准IO提供三种缓存模式:
- 全缓存,即填满IO缓存后才执行IO操作
- 行缓存,即输入输出遇到新行符或者缓存满时,才执行真正的IO操作,stdin,stdout通常是行缓存,当stdout被重定向到一个具体的文件时,那么它是全缓存的
- 无缓存,相当于read write,stderr时不带任何缓存的
带缓存的IO虽然数据复制了两次,但是无需考虑缓存以及最佳IO长度的选择,因此它不比read/write慢多少
如何直观的看到标准IO库的缓存效果,看下面的例子:
int main()
{
char buff[1024];
printf("This Line Should be Cached...");
sleep(3); //这时候在终端上是看不到任何输出
printf("\nThis Line Should be Cached Again"); //这时候可以看到第一个printf的输出,因为被换行符刷新了
sleep(3);
printf("This Line Should Not be Cached Again\n"); //这时候可以看到第二个和第三个printf的输出,因为被结尾的\n刷新
//fgets(buff,20,stdin); // buff中带'\n'
gets(buff); // buff中不带'\n'
printf("%s ",buff);
}
五 目录操作
opendir | 打开目录流 |
readdir | 扫描目录 |
telldir | 返回目录当前位置 |
seekdir | 设置目录流指针 |
closedir | 关闭一个目录流 |
Linux中,与目录操作有关的头文件在diret.h中,它们使用一个名为DIR的结构体作为目录操作的基础,被称为目录流的指针指向这个结构体。
opendir
DIR *opendir(const char *name);
- 打开并建立一个目录流,如果失败,则返回一个空指针
readdir
struct dirent *readdir(DIR *dirp);
- readdir返回一个指针,指向目录流的下一个目录项的有关资料,如果发生错误或者到达目录为,则返回NULL
- struct dirent 包含的内容:
ino_t d_ino: 文件的inode节点号
char d_name[]: 文件的名字
telldir
long int telldir(DIR *dirp);
- 返回值记录一个目录流的当前位置
seekdir
void seekdir(DIR *dirp,long int loc);
- 设置目录流dirp的目录项指针,loc的值用来设置指针位置,它应该通过telldir来获得
closedir
int closedir(DIR *dirp);
- 关闭一个目录流并释放与之关联的资源,执行成功返回0,错误返回-1
六 文件和目录的维护
chmod | 改变文件的访问权限 |
unlink/link/symlink | 删除/建立文件链接 |
mkdir/rmdir | 建立/删除目录 |
chdir/getcwd | 获取当前目录 |
chmod
int chmod(const char *path,mode_t mode);
- path参数指定的文件被修改为具有mode参数给出的权限,参数mode与open中的一样
unlink/link/symlink
int unlink(const char *path);
int link(const char *path1,const char *path2);
int symlink(const char *path1,const char *path2);
- unlink,用来删除一个文件的目录项并减少它的连接数,成功返回0,失败返回-1,如果一个文件的链接数减少到0并且没有进程打开它,这个文件就会被删除
- link 将创建一个指向已有文件path1的新连接,新目录由path2给出
- symlink 以类似的方式创建符号链接
mkdir/rmdir
int mkdir(const char *path,mode_t mode);
int rmdir(const char *path);
- mkdir 用于创建目录,权限由mode参数给出
- rmdir 用于删除目录,只有在目录为空时才行
chdir/getcwd
int chdir(const char *path);
char *getcwd(char *buf,size_t size);
- chdir 用于切换目录
- getcwd 用于获取当前目录,把当前目录的名字写到buff里面,size参数给出了buff的长度
七 /proc文件系统
Linux提供了一个特殊的文件系统procfs,它通常以/proc目录的形式呈现
该目录中包含了许多驱动程序和内核信息,只要应用程序具有正确的访问权限,它们就可以通过读写这些文件来获得信息或者设置参数
- 这是我阿里云服务器的/proc目录列表
1 143 23 430 54 6875 985 interrupts modules thread-self
10 15 24 431 55 6893 acpi iomem mounts timer_list
11 16 274 446 56 6894 buddyinfo ioports mtrr timer_stats
11293 163 27448 47 57 6911 bus irq net tty
11296 165 27449 4700 573 7 cgroups kallsyms pagetypeinfo uptime
12 166 27456 474 58 7081 cmdline kcore partitions version
13 17 27457 479 59 786 consoles keys sched_debug version_signature
133 18 27458 48 599 8 cpuinfo key-users schedstat vmallocinfo
134 19 27507 49 60 81 crypto kmsg scsi vmstat
135 197 28 5 61 811 devices kpagecgroup self zoneinfo
137 2 29 50 62 82 diskstats kpagecount slabinfo
138 20 3 504 6539 874 dma kpageflags softirqs
139 20824 30 505 6559 882 driver loadavg stat
14 21 31 51 6581 9 execdomains locks swaps
140 218 394 52 6584 930 fb mdstat sys
141 22 411 5220 68 952 filesystems meminfo sysrq-trigger
142 22921 425 53 6857 953 fs misc sysvipc
- 常用的信息
cat /proc/cpuinfo 输出cpu信息
cat /proc/meminfo 输出内存使用情况
cat /proc/version 输出内核版本信息
... ...
八 锁文件
Linux提供了很多种方法来实现文件锁定,其中最简单的方法就是以原子操作的方式创建锁文件,所谓“原子操作”就是在创建锁文件时,这个过程不允许被打断。
这种方式却把它所创建的文件是唯一的,而且这个文件不可能被其他程序在同一时间创
锁文件只是建议锁,而不是强制锁
建议锁:进程在对某一个文件进行操作时,没有检测是否加锁或者直接向文件写入数据,内核是不会加以阻止的
强制锁:OS内核的文件锁,应用程序对文件进行读写操作时,OS内核会检测文件是否加锁,如果加锁将导致操作失败锁文件的实现是通过open函数调用的O_EXCL标志来完成的
- 示例代码
/*
* 文件锁
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
int main()
{
int file_desc;
int save_error;
file_desc = open("./LCK.test",O_RDWR | O_CREAT | O_EXCL,0444);
if(file_desc == -1)
{
save_error = errno;
printf("open failed with error %d \n",save_error);
}
else
{
printf(" open succeeded \n");
}
exit(EXIT_SUCCESS);
}
通过O_EXCL标志以原子操作的方式创建了一个锁文件,但是需要注意以下两点:
- 1 如果需要保证这个文件的名字是唯一的,那么所有的进程在创建文件时都需要加上O_EXCL,如果这个文件已经存在,则open()调用会返回错误
- 2 如果其他进程不加O_EXCL标志,则可以直接读写这个文件,因为锁文件是建议锁而不是强制锁
九 文件锁
Linux至少提供两种系统调用,分别是fcntl系统调用和lockf系统调用,这些系统调用的好处是可以实现文件的区域锁定和段锁定
fcntl和lockf使用不同的底层实现,因此两者不能混合使用
fcntl和lockf都是建议锁,而不是强制锁
fcntl系统调用
- fcntl对一个打开的文件描述符进行操作,并能根据command参数完成不同的任务
int fcntl(int fildes,int command,struct flock *flock_structure);
- command选项如下:
/* 获取锁信息,信息存储在 struct flock 结构体中 */
F_GETLK
/* 加锁或者解锁,加锁或者解锁的信息在 struct flock 结构体中 */
F_SETLK
/* 与SETLK类似,但在无法获取锁时,这个调用将等待直到 1 获取锁 2 收到一个信号 才会返回 */
F_SETLKW
- struct flock的成员如下:
short l_type
short l_whence
off_t l_start
off_t l_len
pid_t l_pid
- l_type
/*
* 共享锁/读锁
* 许多不同的进程可以拥有文件同一区域的共享锁
* 只要任一进程拥有共享锁,则没有进程可以获得该区域的独占锁
* 简单的说,这把锁的作用是使文件不让进程上锁
* 要想获取共享锁,文件必须以读或者读写的方式打开
* 一般读文件的进程设置共享锁
*/
F_RDLCK
/*
*解锁,清除锁
*/
F_UNLCK
/*
* 独占锁/写锁
* 有且只有一个进程可以在文件的特定区域拥有一把独占锁
* 只要有一个进程设置了独占锁,其他任何进程都不可以设置任何锁
* 获取独占锁的前提是,文件必须要以写或者读写的方式打开,(否则没有获取独占锁,因为不需要修改文件)
* 一般写文件的进程设置独占锁
*/
F_WRLCK
- l_whence
/* 文件头 */
SEEK_SET
/* 当前位置 */
SEEK_CUR
/* 文件尾 */
SEEK_END
l_start / l_len
l_whence定义了l_start的相对偏移值,l_start定义了该区域的第一个字节,l_len定义了改区域的字节数l_pid
l_pid记录 持有锁的进程
示例代码
1 在文件上加锁
/*
* 文件锁
* use fcntl
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
const char *test_file = "./tmp/test_lock.txt";
/*
The structure describing an advisory lock. This is the type of the third
argument to `fcntl' for the F_GETLK, F_SETLK, and F_SETLKW requests.
struct flock
{
__off_t l_start; Offset where the lock begins.
__off_t l_len; Size of the locked area; zero means until EOF.
__pid_t l_pid; Process holding the lock.
short int l_type; Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK.
short int l_whence; Where `l_start' is relative to (like `lseek').
};
*/
int main()
{
int file_desc;
int byte_count;
char * byte_to_write = 'A';
struct flock region_1;
struct flock region_2;
int res;
file_desc = open(test_file,O_RDWR | O_CREAT , 0666);
if(!file_desc)
{
fprintf(stderr,"unable to open file \n");
exit(EXIT_FAILURE);
}
for(byte_count = 0;byte_count < 100;byte_count ++)
{
write(file_desc,byte_to_write,1);
}
/* 10-30 字节设置为区域 1 ,设置共享锁 */
region_1.l_type = F_RDLCK;
region_1.l_whence = SEEK_SET;
region_1.l_start = 10;
region_1.l_len = 20;
/* 40-50 字节设置为区域 2 ,设置独占锁 */
region_2.l_type = F_WRLCK;
region_2.l_whence = SEEK_SET;
region_2.l_start = 40;
region_2.l_len = 10;
/* 锁定文件 */
printf(" process %d locking file \n ",getpid());
res = fcntl(file_desc,F_SETLK,®ion_1); /* F_SETLK : 区域加锁 */
if(res == -1) fprintf(stderr,"failed to lock region 1\n");
res = fcntl(file_desc,F_SETLK,®ion_2); /* F_SETLK : 区域加锁 */
if(res == -1) fprintf(stderr,"failed to lock region 2\n");
sleep(60);
printf("process %d close file \n",getpid());
close(file_desc);
exit(EXIT_SUCCESS);
}
2 在另一个进程中读出这些锁
/*
* 测试文件中不同部分的文件锁
* use fcntl
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
const char *test_file = "./tmp/test_lock.txt";
#define SIZE_TO_TRY 5
void show_lock_info(struct flock * lck);
int main()
{
int file_desc;
int res;
struct flock region_to_test;
int start_byte;
file_desc = open(test_file,O_RDWR | O_CREAT,0X666);
if(!file_desc)
{
fprintf(stderr,"Unable to open file \n");
}
for(start_byte = 0;start_byte < 99 ;start_byte += SIZE_TO_TRY)
{
/* 独占锁 */
region_to_test.l_type = F_WRLCK;
region_to_test.l_whence = SEEK_SET;
region_to_test.l_start = start_byte;
region_to_test.l_len = SIZE_TO_TRY;
region_to_test.l_pid = -1;
printf("testing F_WRLCK on region from %d to %d \n",start_byte,start_byte+SIZE_TO_TRY);
/* F_GETLK : 获取锁信息 */
res = fcntl(file_desc,F_GETLK,®ion_to_test);
if(res == -1)
{
fprintf(stderr,"lock fail,F_WRLCK retutn \n");
exit(EXIT_FAILURE);
}
if(region_to_test.l_pid != -1)
{
printf("lock fail,F_WRLCK retutn \n");
show_lock_info(®ion_to_test);
}
else
{
printf(" F_WRLCK - Lock would succeed \n");
}
/* 共享锁 */
region_to_test.l_type = F_RDLCK;
region_to_test.l_whence = SEEK_SET;
region_to_test.l_start = start_byte;
region_to_test.l_len = SIZE_TO_TRY;
region_to_test.l_pid = -1;
printf("testing F_RDLCK on region from %d to %d \n",start_byte,start_byte+SIZE_TO_TRY);
/* F_GETLK : 获取锁信息 */
res = fcntl(file_desc,F_GETLK,®ion_to_test);
if(res == -1)
{
fprintf(stderr,"lock fail,F_RDLCK retutn \n");
exit(EXIT_FAILURE);
}
if(region_to_test.l_pid != -1)
{
printf("lock fail,F_RDLCK retutn \n");
show_lock_info(®ion_to_test);
}
else
{
printf(" F_RDLCK - Lock would succeed \n");
}
}
close(file_desc);
exit(EXIT_SUCCESS);
}
void show_lock_info(struct flock * lck)
{
printf(" \t1_type %d ", lck->l_type);
printf(" \t1_whence %d ", lck->l_whence);
printf(" \t1_start %d ", lck->l_start);
printf(" \t1_len %d ", lck->l_len);
printf(" \t1_pid %d \n", lck->l_pid);
}
lockf系统调用
int lockf(int fildes,int function,off_t size_to_lock);
- function定义如下:
F_ULOCK:解锁
F_LOCK : 设置独占锁
F_TLOCK : 测试并设置独占锁
F_TEST : 测试其他进程设置的锁
- size_to_lock
操作的字节数,从文件的当前偏移值开始计算
lockf的接口更加简单,但是功能和灵活性比fcntl差一些
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!