c - 多线程会做write()交错吗

标签 c multithreading

如果我有两个线程,thread0thread1thread0可以:

const char *msg = "thread0 => 0000000000\n";
write(fd, msg, strlen(msg));
thread1可以:
const char *msg = "thread1 => 111111111\n";
write(fd, msg, strlen(msg));

输出会交错吗?例如。
thread0 => 000000111
thread1 => 111111000

最佳答案

首先,请注意,您的问题是“是否将对数据进行交织?”,而不是“是否write()调用[需要]是原子的?”这些是不同的问题...

“TL; DR”摘要:

小于或等于write()字节的管道或FIFO中的

  • PIPE_BUF不会被交错
  • write()对其他任何内容的调用将介于“可能不会被交错”到“永远不会被交错”与“几乎肯定不会被交错”到“赢得”的大多数实现之间的范围内。永远不会被交错”范围。

  • 完整答案

    如果要写入管道或FIFO,则对于write()或更少字节的PIPE_BUF调用,您的数据将完全不会被交织。

    每个the POSIX standard for write() (请注意粗体部分):

    RATIONALE

    ...

    An attempt to write to a pipe or FIFO has several major characteristics:

    • Atomic/non-atomic: A write is atomic if the whole amount written in one operation is not interleaved with data from any other process. This is useful when there are multiple writers sending data to a single reader. Applications need to know how large a write request can be expected to be performed atomically. This maximum is called {PIPE_BUF}. This volume of POSIX.1-2008 does not say whether write requests for more than {PIPE_BUF} bytes are atomic, but requires that writes of {PIPE_BUF} or fewer bytes shall be atomic.

    • ...



    POSIX标准在Windows系统上的适用性至多是有争议的。

    因此,对于管道或FIFO,不会将数据交织到PIPE_BUF字节以内。

    这如何应用于文件?

    首先,文件追加操作必须是原子的。根据相同的POSIX标准(同样,请注意粗体部分):

    If the O_APPEND flag of the file status flags is set, the file offset shall be set to the end of the file prior to each write and no intervening file modification operation shall occur between changing the file offset and the write operation.



    另请参阅Is file append atomic in UNIX?

    那么,这如何适用于非追加的write()调用?

    实现的共性。有关示例,请参见Linux read/write syscall implementations。 (不过,请注意,“问题”直接交给了VFS实现,因此答案也可能是“它很可能取决于您的文件系统...”)

    内核内部write()系统调用的大多数实现都将使用相同的代码来执行附加模式和“正常” write()调用的实际数据写入-以及pwrite()调用。唯一的区别是所使用的偏移量的来源-对于“正常”的write()调用,所使用的偏移量将是当前文件的偏移量。对于追加write()调用,使用的偏移量将是文件的当前结尾。对于pwrite()调用,使用的偏移量将由调用方提供(除非Linux损坏-它使用当前文件大小而不是提供的offset参数作为在追加模式下打开的文件上pwrite()调用的目标偏移量。请参见“BUGS” the Linux pwrite() man page.的部分)

    因此,追加数据必须是原子的,并且几乎可以肯定地将相同的代码用于所有实现中的非追加write()调用。

    但是,“必须在原子上”要求中的“写操作”允许返回的字节数少于所请求的字节总数:

    The write() function shall attempt to write nbyte bytes ...



    即使在追加操作中也允许write()部分结果。但是即使那样,确实要写入的数据也必须是原子写入的。

    部分write()的几率是多少?这取决于您要写的内容。我从未见过磁盘填充以外的文件的部分write()结果或实际的硬件故障。甚至是部分read()结果。我无法看到write()操作的所有方式,该操作将所有数据都存储在内核内存中的单个页面上,从而导致除了磁盘已满或发生硬件故障以外的其他任何原因,导致部分write()出现。

    如果再次查看Is file append atomic in UNIX?,您会看到实际测试表明追加write()操作实际上是原子的。

    因此,答案是“多线程会交错写入吗?”是,“不,只要数据不跨越内核空间中的页面边界,几乎可以肯定不会对4KB(页面大小)以下的写入数据进行交织。”甚至跨越页面边界可能也不会改变太多。

    如果您要写入少量数据,则取决于您是否愿意处理交错数据的几乎肯定甚至从未发生但可能会发生的结果。如果它是文本日志文件,我认为这没关系。

    请注意,使用多个线程写入同一个文件可能不会更快—内核很可能会锁定内容并有效地对实际的write()调用进行单线程处理,以确保它可以满足写入的原子性要求。管道并附加到文件。

    关于c - 多线程会做write()交错吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43648347/

    相关文章:

    c++ - extern "C"在 C 中是否有任何影响?

    c++ - 我应该如何将 C++ 元程序与 C 代码进行比较? (运行 )

    java - Hibernate 和线程修改同一实体

    python - 使用 Python,如何在后台等待按键时在前台运行循环?

    multithreading - Powershell,Stop-Job花费的时间太长

    c - STM32 - 从多个任务中读取 I/O

    C - 将 kbhit 中的 key 写入文件会使程序崩溃

    C - 右移时看似无符号的 int 被符号扩展?

    c++ - 使用 gdb 处理信号

    python - 实现此线程的不同方法?