You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言建议性文件锁程序无法锁定文件,请求故障排查

你的建议性文件锁失效的原因与修复方案

嘿,我帮你梳理了代码里的几个关键错误,正是这些问题导致锁机制完全不起作用:

1. 最致命的错误:混淆文件描述符和文件流指针

你把fopen()返回的FILE*(文件流指针)直接赋值给了int fd(文件描述符),但fcntl()系统调用只认整数类型的文件描述符!这就好比你拿一把汽车钥匙去开房门——完全不匹配,锁操作自然直接失效。

另外,open()的第二个参数是宏常量(比如O_WRONLY、O_RDWR),不是字符串"w"!你用字符串会被编译器转成乱码整数,导致open调用直接失败,后续逻辑全走偏了。

2. 锁的类型和逻辑完全混乱

  • 你要阻止其他进程编辑文件,应该用F_WRLCK(排他写锁),但你设置的是F_RDLCK(共享读锁)——读锁本来就允许多个进程同时读,根本拦不住编辑。
  • 你的Lock()函数刚把锁加上,立刻又解锁了,锁的生命周期连一瞬间都不到,其他进程根本没机会察觉到锁的存在。

3. 文件操作的资源管理一团糟

你反复打开、关闭文件,还多次给同一个fd变量乱赋值,导致文件描述符要么泄漏,要么指向错误的资源。比如readfile()函数里,你明明传了fPtr参数,结果却用全局变量fd来读,这完全是驴唇不对马嘴。

4. 还有几个细节小错误

  • main()函数的标准返回类型是int,不是void,虽然编译器可能放过,但这是C语言的基本规范。
  • Add()函数里的fgets会读取之前scanf留下的换行符,导致你输入的内容直接为空,这个体验也很差。

修复后的完整代码

我把这些问题都修好了,你可以直接参考:

#include <stdio.h>
#include <stdlib.h>
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int controller;
char data[1000];
// 全局文件描述符,保持文件打开以持有锁
int fd = -1;
struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};

void clrscr();
void Operations();
void Add();
void readfile(int fd);
int LockFile();
void UnlockFile();

int main() {
    do {
        clrscr();
        
        // 以读写+创建的方式打开文件,获取文件描述符
        fd = open("demo.txt", O_RDWR | O_CREAT, 0666);
        if (fd == -1) {
            perror("Failed to open file");
            sleep(2);
            continue;
        }

        // 先检查文件是否被其他进程锁定
        fl.l_type = F_WRLCK;
        if (fcntl(fd, F_GETLK, &fl) == -1) {
            perror("Failed to check lock status");
        } else if (fl.l_type != F_UNLCK) {
            printf("File is locked by process %d - only read access allowed\n", fl.l_pid);
            readfile(fd);
            close(fd);
            fd = -1;
            sleep(3);
            continue;
        } else {
            printf("File is available, locking for editing...\n");
            if (LockFile() == 0) {
                printf("Lock acquired successfully!\n");
                readfile(fd);
            }
        }

        printf("\n\t\t***** SIMPLE TEXT EDITOR WITH ADVISORY LOCKING *****\n");
        Operations();

        // 操作完成后解锁并关闭文件
        if (fd != -1) {
            UnlockFile();
            close(fd);
            fd = -1;
        }

    } while(1);

    return 0;
}

// 获取排他写锁
int LockFile() {
    if (fd == -1) return -1;

    fl.l_type = F_WRLCK;
    fl.l_whence = SEEK_SET;
    fl.l_start = 0;
    fl.l_len = 0; // 0表示锁定整个文件
    fl.l_pid = getpid();

    if (fcntl(fd, F_SETLK, &fl) == -1) {
        perror("Failed to set exclusive lock");
        return -1;
    }
    return 0;
}

// 释放锁
void UnlockFile() {
    if (fd == -1) return;

    fl.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &fl) == -1) {
        perror("Failed to unlock file");
    } else {
        printf("File unlocked successfully\n");
    }
}

void clrscr() {
    system("@cls||clear");
}

void Operations() {
    printf("\n\n\tAvailable Operations:\n");
    printf("\t1. Append to File\n\t2. Delete File\n\t3. Exit\n");
    printf("\n\tEnter your choice: ");
    
    // 清除scanf遗留的换行符,避免影响后续fgets
    while(getchar() != '\n');
    scanf("%d", &controller);

    switch(controller) {
        case 1: Add(); break;
        case 2: 
            if (fd != -1) {
                close(fd);
                fd = -1;
            }
            if (remove("demo.txt") == 0) {
                printf("File deleted!\n");
            } else {
                perror("Failed to delete file");
            }
            sleep(2);
            break;
        case 3: 
            if (fd != -1) {
                UnlockFile();
                close(fd);
            }
            exit(EXIT_SUCCESS);
        default:
            printf("Invalid choice, try again\n");
            sleep(2);
    }
}

void Add() {
    if (fd == -1) {
        printf("Can't edit - file is not locked or available\n");
        sleep(2);
        return;
    }

    printf("Enter content to append: \n");
    while(getchar() != '\n'); // 清除换行符
    fgets(data, sizeof(data), stdin);

    // 移动到文件末尾写入
    lseek(fd, 0, SEEK_END);
    write(fd, data, strlen(data));

    printf("Content added successfully!\nUpdated file content:\n\t");
    lseek(fd, 0, SEEK_SET);
    readfile(fd);
    sleep(3);
}

void readfile(int file_fd) {
    char c;
    // 逐个字符读取文件内容
    while (read(file_fd, &c, 1) > 0) {
        printf("%c", c);
    }
    printf("\n");
    // 重置文件指针到开头
    lseek(file_fd, 0, SEEK_SET);
}

修复要点说明

  1. 统一使用文件描述符:全程用open()/close()/fcntl(),彻底抛弃fopen()的混用问题,确保锁操作有效。
  2. 正确的锁类型:用F_WRLCK排他锁,真正阻止其他进程的写操作。
  3. 合理的锁生命周期:在文件打开期间持有锁,操作完成后才解锁,让其他进程有机会检测到锁的存在。
  4. 锁检查逻辑:打开文件后先调用F_GETLK检查是否有其他进程持锁,符合建议性锁的使用规范。
  5. 修复输入问题:解决了scanf和fgets的换行冲突,避免输入为空的问题。

最后要提醒你:建议性锁的前提是所有访问文件的进程都主动检查锁,如果有进程直接打开文件而不调用fcntl检查锁,它依然能编辑文件——这是Unix/Linux建议性锁的设计特性,不是代码bug哦。

内容的提问来源于stack exchange,提问作者xxxxxxxxxxxxxx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:08:43