【问题标题】:thread safety of read/pread system calls读/读系统调用的线程安全
【发布时间】:2011-03-11 02:22:03
【问题描述】:

我很少有与多线程环境中的 read()/pread() 系统调用相关的查询

我正在使用基于 freeBsd 的 Mac-OSX,如果有任何帮助的话 我只在读取模式下使用这个文件,而不是读/写 而且语言是c/c++

假设我们在磁盘上有一个文件 AAAABBBBCCCCDDDEEEE....

文件的一页可以容纳 4 个字母

所以第1页:AAAA

第2页:BBBB .....等等

现在我从具有相同文件描述符的两个不同线程启动读取系统调用 我的意图是从线程 1 读取第一页,从线程 2 读取第二页,..等等。

读取(fd,buff,sizeof(page));

从手册页中我了解到 read 也会增加文件指针,所以我肯定会得到像这样的乱码响应

ABCC ABBB ..等(无特定顺序)

为了解决这个问题,我可以使用 pread()

"Pread() 执行相同的功能,但从特定的 在文件中指定位置而不修改文件指针”//来自手册页

但我不确定使用 pread 是否真的能帮助我实现目标,因为即使它不会增加内部文件指针,也不能保证响应不会混乱。

我所有的数据都是页面对齐的,我想从每个线程中读取一页

线程 1 读取:AAAA 线程2读取:BBBB 线程 3 读取:CCCC ... 没有真正乱码内容..

我还发现了一个帖子Is it safe to read() from a file as soon as write() returns?

但它不是很有用。

我也不确定 read() 是否真的会出现我正在考虑的问题。我正在读取的文件是二进制文件,因此我很难快速手动读取和验证..

任何帮助将不胜感激

【问题讨论】:

    标签: c multithreading asynchronous thread-safety


    【解决方案1】:

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

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

    【讨论】:

    【解决方案2】:

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

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

    请注意all file locking mechanisms are subtly broken on some configurations on all platforms

    【讨论】:

    • 请注意,很多文件锁定在线程之间不起作用,只能在进程之间起作用。我不记得 fcntl 但不相信它。测试一下。
    • fcntl 实际上是进程之间的锁定。 linux.die.net/man/2/fcntl 如果您使用的是 pthread,该库提供了 pthread_rwlock_* 函数来实现每个线程的读/写锁定。但它不提供范围锁定,您必须自己编写...
    【解决方案3】:

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

    【讨论】:

    • 这是一种补救措施,但它会将 I/O 限制为一个线程,我不想这样做,因为我只对阅读感兴趣,而不是读写
    • 我认为如果不阻塞 I/O 上的一个线程就不会这样做。此外,如果您只在简单读取期间阻塞,而不是在线程的整个执行期间阻塞,则等待应该是最少的。唯一的另一种选择是让每个线程使用自己的文件描述符打开文件,但是您必须知道每个线程正在读取什么才能忽略该信息。这也会减慢线程,因为 I/O 会增加一倍。
    • 这是不必要的,也不是 OP 问题的答案。 pread 的全部意义在于做 OP 想要的,答案是肯定的,它是安全的。
    • 我不知道这些功能。我想我从来没有过这种需要。每天学些新东西。唯一的缺点是,您仍然必须知道其他线程正在处理什么,这样您就不会加倍。
    猜你喜欢
    • 2020-06-26
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多