我对多线程环境中的
read()
/pread()
系统调用有一些疑问
我正在使用基于 freeBsd 的 Mac-OSX,如果这有任何帮助的话 我仅在读取模式下使用此文件,而不是读/写 而且语言是c/c++
假设我们磁盘上有一个文件:
AAAABBBBCCCCDDDEEEE...
4 个字母适合文件的一页
所以第1页:AAAA
第2页:BBBB ......等等
现在我从具有相同文件描述符的两个不同线程发起读取系统调用。
我的目的是从线程 1 读取第一页,从线程 2 读取第二页,......等等。
read(fd,buff,sizeof(page));
从手册页中我了解到读取也会增加文件指针,所以我肯定会得到像
这样的乱码响应ABCC ABBB ..等(没有特定顺序)
为了解决这个问题,我可以使用
pread()
来自手册页:
Pread() - 执行相同的功能,但从文件中的指定位置读取而不修改文件指针
但我不确定使用 pread 是否真的能帮助我实现我的目标,因为即使它不会增加内部文件指针,也不能保证响应不会混乱。
我的所有数据都是页面对齐的,我想从每个线程读取一页,例如:
第 1 条内容为:AAAA
主题 2 内容为:BBBB
线程 3 内容为:CCCC ...但实际上并没有乱码内容..
我还发现了一篇文章 write() 返回后立即从文件中 read() 是否安全?
但它不是很有用。
我也不确定
read()
是否真的会出现我正在考虑的问题。我正在读取的文件是一个二进制文件,因此快速手动读取和验证有点困难..
任何帮助将不胜感激
read
和 write
更改底层打开文件的位置。它们是“线程安全”的,因为如果多个线程同时使用它们在同一个打开的文件上执行 IO,您的程序不会出现未定义的行为(崩溃或更糟),但操作的顺序和原子性可能会有所不同,具体取决于文件类型和实现。
另一方面,
pread
和 pwrite
不会更改打开文件中的位置。它们被添加到 POSIX 中正是为了您想要的目的:从多个线程或进程对同一个打开的文件执行 IO 操作,而操作不会干扰彼此的位置。如果您将 pread
和 pwrite
(或多次调用 pwrite
)与文件的重叠部分混合,您仍然可能会遇到一些订购问题,但只要避免这种情况,它们就完全安全为了你想做的事。
fcntl
咨询锁是对文件的范围 的锁定。 您可能会发现这对于序列化对同一区域的读取和写入非常有用,同时允许不同区域上的并发。
int rc;
struct flock f;
f.l_type = F_RDLCK; /* or F_WRLCK */
f.l_whence = SEEK_SET;
f.l_start = n;
f.l_len = 1;
while ((rc = fcntl(fd, F_SETLKW, &f)) == -1 && errno = EINTR)
;
if (rc == -1)
perror("fcntl(F_SETLKW)");
else {
/* do stuff */
f.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &f);
}
一次允许多个读取器锁,而单个写入器锁会阻止所有其他锁。
在两个线程之间共享互斥锁,在读取之前启用线程中的锁,并在正确读取完成时解锁该锁。请参阅
pthread_mutex_create
、pthread_mutex_lock
和 pthread_mutex_unlock
。