Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to lock file using flock with file descriptor

First let me show what works. If I use flock with the file path, it works.

Terminal 1:

[root@centos ~]# flock -x -n /tmp/foo.txt -c "sleep 100"

Terminal 2:

[root@centos ~]# flock -x -n /tmp/foo.txt -c "sleep 100"
[root@centos ~]# echo $?
1

The above output shows that I first acquire an exclusive lock on /tmp/foo.txt in the first terminal. Then in the second terminal, when I try to acquire a lock on the same file, it fails.

Now let me know what does not work. If I use flock with file descriptor, it does not work.

Terminal 1:

[root@centos ~]# { flock -x -n 100; sleep 100; } 100> /tmp/foo.txt

Terminal 2:

[root@centos ~]# { flock -x -n 100; sleep 100; } 100> /tmp/foo.txt

The above output shows that I first try to acquire a lock on /tmp/foo.txt in the first terminal. Then in the second terminal, when I try to acquire a lock on the same file, it succeeds. I expected it to fail just like in the previous example. Why does it succeed?

like image 305
Lone Learner Avatar asked Jun 05 '15 04:06

Lone Learner


1 Answers

You are using -n which will terminate if the lock cannot be acquired immediately and flock will fail with exit code 1. Therefore after you execute your the code in the first terminal, it sleeps for 100 seconds. Next when you execute the same in another terminal, flock fails and returns 1, but because there is a ; and you do not do anything with the return code, the shell simply continues to execute the next statement and sleeps for 100 seconds.

Therefore you need to take decision on the return code of flock as below.

( flock -x -n 100 || exit 55; sleep 100; ) 100> /tmp/foo.txt

Now if you execute the above line in one terminal it will sleep for 100 seconds. Next if you run the code on another terminal it will immediately return to prompt. Do an echo $? and you will see that it has returned 55 as we wanted to return using the || .

What the || does is short-circuiting. If flock returns 0 as in normal exit which is a true value for the shell, it will not execute the right hand side of the expression and therefore go to the next statement. If the return value is 1 which is a false for the shell, it will continue to evaluate the right hand side expression which is exit 55 and therefore exit. You can do this by if-then-fi also.

Also note that I have used brackets () instead of curly braces {}. This is because, if you use the curley-braces then the commands will be executed in the current shell and if you use exit, then it will exit from the current shell. A bracket will create a subshell, therefore doing an exit from there terminates the subshell and gets back you to your original shell.

It worked for your first example using -c because there you have the single command enclosed within the flock argument. Therefore if flockis unable to acquire the lock it will simply not execute the statement and terminate.

like image 103
phoxis Avatar answered Oct 09 '22 14:10

phoxis