fcntl() is the one API to choose, since it is the least broken and is POSIX. It is the only one that works across NFS. That said it is a complete disaster, too, since locks are bound to processes, not file descriptors. That means that if you lock a file and then some other thread or some library function locks/unlocks it, your lock will be broken too. Also, you cannot use file system locks to protect two threads of the same process to interfere with each other. Also, you should not use file locks on files that are accessible to more than one user, because that effectively enables users to freeze each others processes.
In summary: file locking on Unix creates more problems than it solves. Before you use it you need to be really sure you fully understand the semantics.