Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何检查文件是否已在C中打开_C_Linux - Fatal编程技术网

如何检查文件是否已在C中打开

如何检查文件是否已在C中打开,c,linux,C,Linux,我正在一个多线程系统上工作,在这个系统中,文件可以根据文件访问权限在不同的线程之间共享 如何检查文件是否已被其他线程打开?您可以使用将文件标记为已锁定,也可以检查文件是否已锁定 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. M

我正在一个多线程系统上工作,在这个系统中,文件可以根据文件访问权限在不同的线程之间共享

如何检查文件是否已被其他线程打开?

您可以使用将文件标记为已锁定,也可以检查文件是否已锁定

   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及其潜在弱点的更多信息。

要了解是否已在上打开命名文件,您可以扫描
/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;
从您的评论来看,如果先前调用文件上的
fopen()
已经创建了一个现有的
文件*
,那么您要做的似乎是检索该文件。标准C库没有提供遍历当前打开的所有
文件*
的机制。如果有这样一种机制,您可以使用
fileno()
派生其文件描述符,然后使用
readlink()
查询
/proc/self/fd/#
,如上所示


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

我对Windows上的多线程不太了解,但是如果您使用Linux,您可以有很多选择是一种奇妙的资源。您还可以利用任何(例如:
fcntl
)。更多关于Linux锁的信息。创建和手动管理自己的互斥锁比其他方式提供了更大的灵活性
user814064
关于
flock()
的评论看起来是完美的解决方案,但拥有选择从来都没有坏处

添加了一个代码示例:

#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;
}
#包括
#包括
#包括
文件*fp;
整数计数器;
pthread\u mutex\u t fmutex=pthread\u mutex\u初始值设定项;
void*foo(){
//pthread_mutex_trylock()检查互斥体是否正确
//无阻塞锁定
//int busy=pthread\u mutex\u trylock(&fmutex);
//这会一直阻止,直到释放锁为止
pthread_mutex_lock(&fmutex);
fprintf(fp,“计数器=%d\n”,计数器);
printf(“计数器=%d\n”,计数器);
计数器++;
pthread_mutex_unlock(&fmutex);
}
int main(){
计数器=0;
fp=fopen(“threads.txt”,“w”);
pthread_t thread1,thread2;
if(pthread_create(&thread1,NULL,&foo,NULL))
printf(“创建线程1时出错”);
if(pthread_create(&thread2,NULL,&foo,NULL))
printf(“创建线程2时出错”);
pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
fclose(fp);
返回0;
}

如果您倾向于在shell中执行此操作,那么只需使用
lsof$filename
即可。如果您需要确定是否有另一个线程打开了一个文件,而不是知道某个文件已经打开,那么您可能是使用了错误的方法

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

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

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
,则在搜索时没有其他线程打开该文件(由于互斥锁已解锁,其他线程可能在函数执行
返回之前打开了该文件)。如果需要以安全的方式打开文件(即只有一个线程可以打开文件
filename
),则需要使用
my\u file\u open()
函数锁定、搜索、添加新的
my\u文件
,如果未找到,则返回新添加的
my\u文件
指针。如果文件已经存在,那么
my\u file\u open()
可能返回
NULL
,这意味着它无法打开一个线程可以使用的文件(即另一个线程已经在使用它)

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

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


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

您需要物理锁,或者跨线程定义信号量(驻留在共享内存中?),最简单的方法是保留所有打开文件的共享列表,并使其可供所有线程使用。最简单的方法是自己跟踪它。附带说明:如果要检查文件是否已打开(由任何其他进程或线程打开),可以尝试获取文件写入租约(
fcntl(fileno(stream)、F_SETLEASE、F_WRLCK)
)。如果文件已被其他人打开,则它将失败。这仅适用于用户拥有的普通文件。如果其他任何人试图打开该文件,租约所有者将收到一个信号,并有多达
/proc/sys/fs/lease_break_time
秒的时间来操作该文件,并在另一次打开之前释放或降级租约(但最终,即使重命名或取消链接,也会)