6

In C programming, is there a way to achieve timeout on flock()?

Thanks.

#include <sys/file.h>

int flock(int fd, int operation);
user180574
  • 5,681
  • 13
  • 53
  • 94
  • 3
    There's no timeout support, there's only [`LOCK_NB`](https://stackoverflow.com/questions/5507185/what-lock-nb-actually-do-in-flock). If you need a timeout while *waiting for the lock*, you need to interrupt the lock operation with a signal. A python version is [here](https://stackoverflow.com/questions/5255220/fcntl-flock-how-to-implement-a-timeout) – dhke Nov 09 '15 at 17:39
  • 1
    You mean a timeout on calling the function, or a timeout to automaticaly unlock the file after some time? – hexasoft Nov 09 '15 at 17:40
  • 3
    You might be able to use `alarm` or `setitimer` to interrupt yourself after a certain amount of time. – Colonel Thirty Two Nov 09 '15 at 17:41

2 Answers2

1

You can use SIG_ALARM to do it. http://www.gnu.org/software/libc/manual/html_node/Setting-an-Alarm.html It is kind of tricky though, especially if you are dealing with multiple threads. You would have to make sure that your system delivers the sig alarm to the thread that set it always, and it might not be the case... in which case you would need to play with pthread_sigmask http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_sigmask.html to make sure that only your thread has the signal enabled... but what if 2 threads are blocking on flock at the same time? You will need to add some kind of mutex wrapper for that.

MK.
  • 33,605
  • 18
  • 74
  • 111
  • Thanks, I will go with the LOCK_NB approach for the moment. – user180574 Nov 10 '15 at 23:25
  • 1
    the problem with LOCK_NB is that you will be getting the lock with a delay equal to your sleep which is rarely acceptable. – MK. Nov 11 '15 at 01:56
  • Note that "You can only have one timer of each kind set at any given time". This means a code module cannot just set alarms. There must be a process-wide manager that can coordinate all SIGALRM clients. For example: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/basic_deadline_timer/async_wait.html – Wheezil Feb 20 '17 at 16:16
0

If you cannot use SIGALARM for some reason, your other option is busy waiting with LOCK_NB. Both of these options were already mentioned but here is an example with LOCK_NB:

#include <sys/file.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>

int flock_with_timeout(int fd, int timeout) {
    struct timespec wait_interval = { .tv_sec = 1, .tv_nsec = 0 }; // 1 sec
    int wait_total = 0; // Total time spent in sleep

    while (flock(fd, LOCK_EX | LOCK_NB) == -1) {
        if (errno == EWOULDBLOCK) {
            // File is locked by another process
            if (wait_total >= timeout) { // If timeout is reached
                printf("Timeout occurred while waiting to lock file\n");
                return -1;
            }

            sleep(wait_interval.tv_sec);
            wait_total += wait_interval.tv_sec;
        } else {
            perror("flock - failed to lock file");
            return -1;
        }
    }

    return 0;
}

You can use this function like so:

int main() {
    int fd = open("file.txt", O_WRONLY | O_CREAT, 0640);
    if (fd == -1) {
        perror("open - failed to open file");
        return 1;
    }

    if (flock_with_timeout(fd, 5) != 0) {
        close(fd);
        return 1;
    }

    printf("Got the lock\n");
    /* ... you can work with the file here ... */

    // Don't forget to unlock the file
    if (flock(fd, LOCK_UN) == -1) {
        perror("flock - failed to unlock file");
        close(fd);
        return 1;
    }

    close(fd);
    return 0;
}

Note 1: If you are exiting main() and thus terminating the program, you don't need to unlock, nor close the file handle. This will be done automatically.

Note 2: close() may also fail and should be error-checked.

Note 3: As @MK already mentioned, the problem with LOCK_NB is that you will be getting the lock with a delay up to your sleep time which may not be acceptable. In the example we are sleeping for 1 second.

famzah
  • 1,462
  • 18
  • 21