'Use a sequence of write() instead a single write()
I'm programming in C on a Unix system. I know that:
write(fd,"ABCD",4);
is better than do that:
write(fd, "A", 1);
write(fd, "B", 1);
write(fd, "C", 1);
write(fd, "D", 1);
Obviously, I'm not talking about code legibility, but I want to know what problems the second methodology could give. Do we talk about the atomicity of execution? If yes why?
Thanks
Solution 1:[1]
You are right to be worried about atomicity here.
If another process, or another thread within the same process, is also writing to the same communications channel, then
write(fd, "ABCD", 4);
will write the four bytes "ABCD" atomically, in the sense that output from the other writers cannot appear in the middle of those four bytes. On the other hand,
write(fd, "A", 1);
write(fd, "B", 1);
write(fd, "C", 1);
write(fd, "D", 1);
will write each byte separately, and output from the other writers can appear in between the letters.
However, atomicity is only guaranteed for short writes, where the third argument is smaller than the constant PIPE_BUF. If you write more data than that, there is no way to ensure that output from other writers doesn't appear in the middle. PIPE_BUF may be as small as 512 but is usually somewhat larger than that nowadays.
The easiest way to see this for yourself is with fork and writes to standard output:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
} else if (pid == 0) {
// child
write(1, "ABCD", 4); sleep(1);
write(1, "A", 1); sleep(1);
write(1, "B", 1); sleep(1);
write(1, "C", 1); sleep(1);
write(1, "D", 1);
return 0;
} else {
// parent
write(1, "1234", 4); sleep(1);
write(1, "1", 1); sleep(1);
write(1, "2", 1); sleep(1);
write(1, "3", 1); sleep(1);
write(1, "4", 1);
waitpid(pid, 0, 0);
write(1, "\n", 1);
return 0;
}
}
This program will print something like 1234ABCD1AB23CD4. The first ABCD will always appear as a group, and the first 1234 will also always appear as a group, but either one could be first; the second ABCD and 1234 might get mixed up together arbitrarily.
(Quiz question: why did I put the final write(1, "\n", 1) in the parent, after the waitpid?)
Solution 2:[2]
POSIX requires write syscall to be atomic in 2.9.7 Thread Interactions with Regular File Operations:
If two threads each call one of these functions [
writeis one of them], each call shall either see all of the specified effects of the other call, or none of them.
However, write is not required to write the whole requested amount. The maximum size of atomic writes depends on the filesystem. For pipes it is PIPE_BUF.
Note that write is a system call and these calls are much more expensive than regular calls. So, the popular method is to write into a buffer first and when the buffer is full or needs to be flushed immediately only then call write syscall. This is what C I/O library fwrite does for you.
Hence, you may like to prefer minimizing the number of write calls.
Solution 3:[3]
The issue is simply efficiency: Each call requires pushing the parameters onto the stack, then pulling them off in the function, then returning. This is all repeated unnecessarily when you call repeatedly.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | zwol |
| Solution 2 | |
| Solution 3 | daShier |
