C语言使用fcntl对文件加锁

加锁、解锁及测试代码 lock.c

#include 
#include 
#include 
#include 
#include 

#define TRUE  1
#define FALSE 0

/**
 * @brief 尝试获取文件锁
 * @details 获取文件锁时不会阻塞进程, 获取不到锁时,立即返回不会等待
 * @param fd 文件描述符
 * @return 是否成功获取文件锁
 *   @retval TRUE 获取锁成功
 *   @retval FALSE 获取锁失败
 * @attention 这里只是建议性锁,每个使用上锁文件的进程都要检查是否有锁存在,
 * 内核不对读写操作做内部检查和强制保护
 * @see ngx_trylock_fd
 * @ref [http://agentzh.org/misc/code/nginx/os/unix/ngx_files.c.html#L416]
 */
int trylock_fd(int fd)
{
    struct flock  fl;

    memset(&fl, 0, sizeof(struct flock));
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;

    if (fcntl(fd, F_SETLK, &fl) == -1) {
        return FALSE;
    } else {
        return TRUE;
    }
}

/**
 * @brief 获取锁或等待
 * @details 获取文件锁时会阻塞进程, 获取不到锁时,一直等到获取成功
 * @param fd 文件描述符
 * @return 是否成功获取文件锁
 *   @retval TRUE 获取锁成功
 *   @retval FALSE 获取锁失败
 * @attention 这里只是建议性锁,每个使用上锁文件的进程都要检查是否有锁存在,
 * 内核不对读写操作做内部检查和强制保护
 * @see ngx_lock_fd
 * @ref [http://agentzh.org/misc/code/nginx/os/unix/ngx_files.c.html#L433]
 */
int waitlock_fd(int fd)
{
    struct flock  fl;

    memset(&fl, 0, sizeof(struct flock));
    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;

    if (fcntl(fd, F_SETLKW, &fl) == -1) {
        return FALSE;
    } else {
        return TRUE;
    }
}

/**
 * @brief 释放文件锁
 * @param fd 文件描述符
 * @return 是否成功释放文件锁
 *   @retval TRUE 释放锁成功
 *   @retval FALSE 释放锁失败
 * @see ngx_unlock_fd
 * @ref [http://agentzh.org/misc/code/nginx/os/unix/ngx_files.c.html#L450]
 */
int unlock_fd(int fd)
{
    struct flock  fl;

    memset(&fl, 0, sizeof(struct flock));
    fl.l_type = F_UNLCK;
    fl.l_whence = SEEK_SET;

    if (fcntl(fd, F_SETLK, &fl) == -1) {
        return FALSE;
    } else {
        return TRUE;
    }
}

/**
 * @brief 检查是否设置了文件锁
 * @details 检查文件锁状况,并输出相关信息
 * @param fd 文件描述符
 */
void checklock_fd(int fd)
{
    struct flock  fl;

    memset(&fl, 0, sizeof(struct flock));
    fl.l_whence = SEEK_SET;

    if (fcntl(fd, F_GETLK, &fl) == -1) {
        printf("failed to check file lock. detail: %s(%d)\n",
               strerror(errno), errno);
        return;
    } else {
        switch (fl.l_type) {
        case F_UNLCK:
            printf("no file lock\n");
            break;
        case F_RDLCK:
            printf("read lock already set by %d\n", fl.l_pid);
            break;
        case F_WRLCK:
            printf("write lock already set by %d\n", fl.l_pid);
            break;
        }
        return;
    }
}

/**
 * @brief 主函数
 * @details 测试获取锁、检查锁、释放锁的函数
 * @param argc 命令参数个数
 * @param argv 命令参数指针数组
 * @return 程序执行成功与否
 *   @retval 0 程序执行成功
 *   @retval 1 程序执行失败
 */
int main(int argc, char *argv[])
{
    int   fd;
    char *file;
    pid_t pid;

    if (argc == 2) {
        file = argv[1];
    } else {
        file = "file.lock";
    }

    pid = getpid();

    fd = open(file, O_RDWR|O_CREAT, 0666);
    if (fd < 0) {
        fprintf(stderr, "failed to open \"%s\", detail: %s(%d)\n",
                file, strerror(errno), errno);
        exit(1);
    }

    if(trylock_fd(fd)) {
        printf("file has been locked by %d. press any key to unlock\n", pid);
    } else {
        printf("waiting for lock\n");
        checklock_fd(fd);
        waitlock_fd(fd);
        printf("file has been locked by %d. press any key to unlock\n", pid);
    }
    
    getchar();
    unlock_fd(fd);
    printf("file has been unlocked by %d.\n", pid);
    close(fd);
    exit(0);
}

编译

# gcc lock.c -o lock

测试验证

窗口1
# ./lock 
file has been locked by 3286. press any key to unlock
<-- 1) 按任意键,释放锁
file has been unlocked by 3286.
窗口2
# ./lock 
waiting for lock
write lock already set by 3286
<-- 等待锁释放,1)按下任意键后继续
file has been locked by 3287. press any key to unlock
<-- 2) 按任意键,释放锁
file has been unlocked by 3287.

你可能感兴趣的:(C语言使用fcntl对文件加锁)