10

I am working on a multithreaded system where a file can be shared among different threads based on the file access permissions.

How can I check if file is already opened by another thread?

4

5 回答 5

4

要确定一个命名文件是否已经在上打开,您可以扫描/proc/self/fd目录以查看该文件是否与文件描述符相关联。下面的程序勾勒出一个解决方案:

DIR *d = opendir("/proc/self/fd");
if (d) {
    struct dirent *entry;
    struct dirent *result;

    entry = malloc(sizeof(struct dirent) + NAME_MAX + 1);
    result = 0;
    while (readdir_r(d, entry, &result) == 0) {
        if (result == 0) break;
        if (isdigit(result->d_name[0])) {
            char path[NAME_MAX+1];
            char buf[NAME_MAX+1];
            snprintf(path, sizeof(path), "/proc/self/fd/%s",
                     result->d_name);
            ssize_t bytes = readlink(path, buf, sizeof(buf));
            buf[bytes] = '\0';
            if (strcmp(file_of_interest, buf) == 0) break;
        }
    }
    free(entry);
    closedir(d);
    if (result) return FILE_IS_FOUND;
}
return FILE_IS_NOT_FOUND;

从您的评论来看,您想要做的似乎是检索现有文件FILE *,如果已经通过对文件的先前调用创建了一个现有fopen()文件。标准 C 库没有提供任何机制来遍历所有当前打开FILE *的 . 如果有这样的机制,你可以用 导出它的文件描述符fileno(),然后用 查询/proc/self/fd/#readlink()如上所示。

这意味着您将需要使用数据结构来管理您的 open FILE *s。使用文件名作为键的哈希表可能对您最有用。

于 2013-09-06T01:13:26.497 回答
2

您可以使用int flock(int fd, int operation); 将文件标记为已锁定并检查它是否已锁定。

   Apply or remove an advisory lock on the open file specified by fd.
   The argument operation is one of the following:

       LOCK_SH  Place a shared lock.  More than one process may hold a
                shared lock for a given file at a given time.

       LOCK_EX  Place an exclusive lock.  Only one process may hold an
                exclusive lock for a given file at a given time.

       LOCK_UN  Remove an existing lock held by this process.

如果您在每个线程中分别打开文件,flock 应该在线程应用程序中工作: 多个线程能够同时获取flock

有更多关于羊群的信息,它的潜在弱点在这里

于 2013-09-06T01:13:13.087 回答
2

如果您倾向于在 shell 中执行此操作,则可以简单地使用lsof $filename.

于 2013-09-06T01:15:18.900 回答
1

I don't know much in the way of multithreading on Windows, but you have a lot of options if you're on Linux. Here is a FANTASTIC resource. You might also take advantage of any file-locking features offered inherently or explicitly by the OS (ex: fcntl). More on Linux locks here. Creating and manually managing your own mutexes offers you more flexibility than you would otherwise have. user814064's comment about flock() looks like the perfect solution, but it never hurts to have options!

Added a code example:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

FILE *fp;
int counter;
pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;

void *foo() {
        // pthread_mutex_trylock() checks if the mutex is
        // locked without blocking
        //int busy = pthread_mutex_trylock(&fmutex);

        // this blocks until the lock is released
        pthread_mutex_lock(&fmutex);
        fprintf(fp, "counter = %d\n", counter);
        printf("counter = %d\n", counter);
        counter++;
        pthread_mutex_unlock(&fmutex);
}

int main() {

        counter = 0;
        fp = fopen("threads.txt", "w");

        pthread_t thread1, thread2;

        if (pthread_create(&thread1, NULL, &foo, NULL))
                printf("Error creating thread 1");
        if (pthread_create(&thread2, NULL, &foo, NULL))
                printf("Error creating thread 2");

        pthread_join(thread1, NULL);
        pthread_join(thread2, NULL);

        fclose(fp);
        return 0;
}
于 2013-09-06T01:13:47.160 回答
0

如果您需要确定另一个线程是否打开了文件而不知道文件已经打开,那么您可能做错了。

在多线程应用程序中,您希望管理所有线程可访问的列表中共同使用的资源。该列表需要以多线程安全的方式进行管理。这只是意味着您需要锁定 a mutex,对列表执行操作,然后解锁mutex. 此外,由多个线程读取/写入文件可能非常复杂。同样,您需要锁定才能安全地执行此操作。在大多数情况下,将文件标记为“忙碌”(也就是线程正在使用该文件)并等待文件“就绪”(也就是没有线程正在使用它)要容易得多。

因此,假设您有一种链表实现形式,您可以以类似于以下方式搜索列表:

my_file *my_file_find(const char *filename)
{
    my_file *l, *result = NULL;

    pthread_mutex_lock(&fmutex);

    l = my_list_of_files;

    while(l != NULL)
    {
         if(strcmp(l->filename, filename) == 0)
         {
             result = l;
             break;
         }
         l = l->next;
    }

    pthread_mutex_unlock(&fmutex);

    return result;
}

如果函数返回NULL,则在搜索时没有其他线程打开文件(由于互斥锁已解锁,另一个线程可能在函数执行之前打开了文件return)。如果您需要以安全的方式打开文件(即只有一个线程可以打开文件filename),那么您需要一个my_file_open()函数来锁定、搜索、my_file如果未找到则添加新的、然后返回新添加的my_file指针。如果文件已经存在,则my_file_open()可能返回NULL意味着它无法打开一个线程可以使用的文件(即另一个线程已经在使用它)。

请记住,您无法解锁搜索和添加之间的互斥锁。my_file_find()因此,如果不首先锁定互斥锁(在这种情况下,您可能希望拥有递归互斥锁),就不能使用上面的函数。

换句话说,只有先锁定互斥锁,完成所有工作,然后解锁互斥锁,您才能搜索现有列表、扩大现有列表并缩小(也称为关闭文件)。

这适用于任何类型的资源,而不仅仅是文件。它可以是内存缓冲区、图形界面小部件、USB 端口等。

于 2021-05-22T15:30:32.607 回答