Source 1 - Understanding Linux Kernel by Daniel Bovet and Marco Cesati
When a file can be accessed by more than one process, a synchronization problem occurs. Take the following two scenarios as an example -
Concurrent access to a file can, hence, result in unpredictable results. However, there's a solution to this - File Locking!
File locking can be of two types in Linux - Mandatory locking & Advisory (or record) locking. Regardless of whether processes use advisory or mandatory locks, they can use both shared read locks and exclusive write locks.
Several processes can have a shared read lock on some region (or whole file) but only one process can have a write lock on it at the same time. Moreover, it is not possible to get a write lock when another process owns a read lock for the same file region (or whole file), and vice versa, i.e., you cannot get a read lock on a region (or whole file) that is locked for writing.
It is possible to lock an arbitrary region of a file (even a single byte) and hence a process can also hold multiple locks on different parts of the file i.e., it provides granularity. Such types of locks are known as advisory locks. This kind of lock does not keep out another process that is ignorant of locking i.e., the lock doesn’t work unless other processes cooperate in checking the existence of a lock before accessing the file.

Process 1 holds the mandatory write lock on the entire file and hence all the other processes (2, 3, 4 & 5) cannot access the file i.e., they cannot get the write lock (Processes 2 & 3) or the read lock (Processes 4 & 5) on the file.

Process 1, 2 & 4 hold the mandatory read lock on the entire file and hence all the Process 4 cannot access the file i.e., it cannot get the write lock on the file.
fcntl and the flock structure(Source - man page for fcntl system call [man 2 fcntl])
The fcntl() system call can be used to acquire an advisory lock on a file's record. The general syntax of fcntl() system call is show below -
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */);
The commands specific to advisory locking are used -