MST

星途 面试题库

面试题:C语言中Linux文件系统调用的原子操作

在多线程环境下使用C语言进行Linux文件系统调用,为了避免竞态条件对文件操作的影响,有哪些文件系统调用具备原子操作特性?以创建并写入文件为例,说明如何利用这些原子操作特性来保证数据的一致性和完整性,需结合代码示例进行阐述。
41.8万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

具备原子操作特性的文件系统调用

  1. open(O_CREAT | O_EXCL):当使用 open 函数并指定 O_CREAT(如果文件不存在则创建)和 O_EXCL(如果文件已存在则 open 失败)标志时,这两个操作(检查文件是否存在和创建文件)是原子的。这意味着在多线程环境下,不会出现一个线程检查文件不存在,然后在创建文件之前另一个线程也进行同样检查并创建文件的竞态条件。
  2. write:在单个 write 调用中,写入操作是原子的(只要写入的数据量小于或等于系统的 PIPE_BUF 大小,通常为 4096 字节)。对于大于 PIPE_BUF 的写入,内核可能会将其拆分为多个操作,但在每个小于等于 PIPE_BUF 的子操作内是原子的。

利用原子操作特性保证数据一致性和完整性的示例

下面是一个使用 open(O_CREAT | O_EXCL)write 来创建并写入文件的示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

#define FILE_NAME "test.txt"
#define DATA "This is some data to be written.\n"

void* write_to_file(void* arg) {
    int fd = open(FILE_NAME, O_CREAT | O_EXCL | O_WRONLY, 0644);
    if (fd == -1) {
        perror("open");
        pthread_exit(NULL);
    }

    ssize_t bytes_written = write(fd, DATA, strlen(DATA));
    if (bytes_written == -1) {
        perror("write");
    }

    close(fd);
    pthread_exit(NULL);
}

int main() {
    pthread_t thread1, thread2;

    if (pthread_create(&thread1, NULL, write_to_file, NULL) != 0) {
        perror("pthread_create");
        return 1;
    }

    if (pthread_create(&thread2, NULL, write_to_file, NULL) != 0) {
        perror("pthread_create");
        return 1;
    }

    if (pthread_join(thread1, NULL) != 0) {
        perror("pthread_join");
        return 1;
    }

    if (pthread_join(thread2, NULL) != 0) {
        perror("pthread_join");
        return 1;
    }

    return 0;
}

在这个示例中:

  1. 使用 open(O_CREAT | O_EXCL) 确保文件创建操作的原子性,避免多个线程同时创建同名文件。如果文件已经存在,open 调用会失败,这样可以保证每个线程创建文件的操作是互斥的。
  2. 使用 write 函数写入数据,由于写入的数据量小于 PIPE_BUF,所以每个 write 操作是原子的,不会出现数据部分写入或交错的情况。这样就保证了在多线程环境下文件操作的数据一致性和完整性。