read/pread 系统调用的线程安全性

问题描述 投票:0回答:3

我对多线程环境中的

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()
是否真的会出现我正在考虑的问题。我正在读取的文件是一个二进制文件,因此快速手动读取和验证有点困难..

任何帮助将不胜感激

c multithreading asynchronous thread-safety
3个回答
12
投票

read
write
更改底层打开文件的位置。它们是“线程安全”的,因为如果多个线程同时使用它们在同一个打开的文件上执行 IO,您的程序不会出现未定义的行为(崩溃或更糟),但操作的顺序和原子性可能会有所不同,具体取决于文件类型和实现。

另一方面,

pread
pwrite
不会更改打开文件中的位置。它们被添加到 POSIX 中正是为了您想要的目的:从多个线程或进程对同一个打开的文件执行 IO 操作,而操作不会干扰彼此的位置。如果您将
pread
pwrite
(或多次调用
pwrite
)与文件的重叠部分混合,您仍然可能会遇到一些订购问题,但只要避免这种情况,它们就完全安全为了你想做的事。


1
投票

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);
}

一次允许多个读取器锁,而单个写入器锁会阻止所有其他锁。

请注意,所有文件锁定机制在所有平台上的某些配置上都会被巧妙地破坏


-1
投票

在两个线程之间共享互斥锁,在读取之前启用线程中的锁,并在正确读取完成时解锁该锁。请参阅

pthread_mutex_create
pthread_mutex_lock
pthread_mutex_unlock

© www.soinside.com 2019 - 2024. All rights reserved.