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.