linux 多线程写
pread
和 pwrite
函数是 linux 下 C 语言编程中非常好用的 IO 操作函数。它们属于系统调用,在 2.1.60 之后版本的 linux 下都可以使用,尤其适合用于多线程的应用
中,它们允许多个线程操作同一个文件描述符,不会互相影响彼此的文件偏移(offset)。
pread 和 pwrite 函数
所需头文件和函数原型
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
函数说明
pread
和pwrite
函数从文件描述符 fd
(可由open函数获得)描述的文件的 offset
偏移处,读写 count
字节数据。
如果是读,读出的内容通过buf
传出。如果是写,写入的内容由buf
传入。
它俩的返回值与read
和write
函数类似,成功时,pread
和pwrite
函数分别返回成功读出或者写入的字节数。如果调用失败,返回 -1,失败码可从errno
查出。
pread/pwrite 和 read/write 函数的联系和区别
以写入函数为例,pwrite
函数在单线程
的情况下,相当于 lseek
和write
函数的组合:
pwrite(fd, buf, len, offset);
/** 相当于 */
lseek(fd, offset, SEEK_SET);
write(fd, buf, len);
只不过,在 fd
文件描述符没有O_APPEND
属性的情况下,write
函数会修改文件偏移指针,下次不seek
写入位置直接调用write
函数时,write
函数会接着上次的位置继续写入(offset+len)。而pwrite
函数则不会改变文件偏移指针。
另外,很重要的一点是,pwrite
函数的seek
和写入
是原子操作,不会因为进程调度或者其他因素中断。而对于lseek
和write
的组合,因为两个语句之间存在间隙,进程调度线程切换有可能发生在其间,导致写入的数据出错。
pread/pwrite 和 read/write 函数的实例demo对比
下面这段代码的功能很简单,就是创建了两个线程,一个线程负责顺序往 test.bin
文件顺序写入 0~254 的整数,另外一个线程则负责从中顺序读出。编译后,程序接收一个参数,1
表示只从test.bin
中读取,2
表示只往test.bin
中写入,3
表示同时读写test.bin
。
lseek
和read/write
的组合在多线程同时读写中的表现
pread/pwrite
在多线程同时读写中的表现
现在来试试pread/pwrite
函数的表现如何,我们将代码中的lseek
和read/write
注释,取消pread/pwrite
的注释:
...
// lseek(fd, i, SEEK_SET);
// read(fd, &j, 1);
pread(fd, &j, 1, i);
...
// lseek(fd, i, SEEK_SET);
// write(fd, &i, 1);
pwrite(fd, &i, 1, i);
...
再编译,做相同的测试:
$ gcc pread_vs_read.c -lpthread
lcc@lcc-vm:/lccRoot/xx_test/tmp/pread_vs_read$ ./a.out 3
w_thread: 0
r_thread: 0
w_thread: 1
r_thread: 1
...
$ ./a.out 1
r_thread: 0
r_thread: 1
r_thread: 2
r_thread: 3
r_thread: 4
r_thread: 5
...
发现数据被正确写入了。
总结
可以看出,pread/pwrite
更适合在多线程编程中使用。当然,非要用read/write
也可以,只是需要自行做好线程同步,这就比pread/pwrite
麻烦了许多。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2022-10-10 kmalloc vmalloc
2022-10-10 深入理解mv
2022-10-10 linux mmu cpu
2022-10-10 sendfile 系统调用
2022-10-10 curl
2022-10-10 生成https license 以及握手过程