Let's see how combine messages are used.
Consider a case where two threads are executing the following code, trying to read from the same file descriptor:
Atomic a_thread () { char buf [BUFSIZ]; lseek (fd, position, SEEK_SET); read (fd, buf, BUFSIZ); … }
The first thread performs the lseek() and then gets preempted by the second thread. When the first thread resumes executing, its offset into the file will be at the end of where the second thread read from, not the position that it had lseek()'d to.
This can be solved in one of three ways:
Let's look at these three methods.
If this practice isn't enforced, then you still have the exact same problem. For example, suppose one thread that's obeying the convention locks the mutex and does the lseek(), thinking that it's protected. However, another thread (that's not obeying the convention) can preempt it and move the offset to somewhere else. When the first thread resumes, we again encounter the problem where the offset is at a different (unexpected) location. Generally, using a mutex will be successful only in very tightly managed projects, where a code review will ensure that each and every thread's file functions obey the convention.
Another place where combine messages are useful is in the stat() function, which can be implemented by calling open(), fstat(), and close() in sequence.
Rather than generate three separate messages (one for each of the functions), the C library combines them into one contiguous message. This boosts performance, especially over a networked connection, and also simplifies the resource manager, because it's not forced to have a connect function to handle stat().