ReadDir()线程不安全函数

本文详细介绍了readdir函数的使用方法及注意事项,指出readdir不是线程安全的,并提供了两种解决方案:加锁或使用局部变量保存数据。此外还提及了readdir_r函数作为替代方案。

一、readdir函数:      

struct dirent *readdir(DIR *dirp); 

The  data  returned by readdir() may be overwritten by subsequent calls to readdir() for the same directory stream.

成功时,readdir() 返回指向 dirent 结构的指针。(这个结构是静态分配的;不要试图去free(3) 它。)如果到达了上当结尾,NULL 被返回并保持ERRNO不变。如果错误发生了,NULL 被返回并小心设置 ERRNO值。

readdir函数为非线程安全函数;

解决方法:

1、加锁;

2、用局部变量保存数据。

二、线程不安全函数 

多线程不安全函数是指:
一个进程中有很多全局变量以及函数(error、strtok、asctime等),各个线程对这些变量会产生干扰。在多线程运行期库中每个线程有自己的本地存储空间,有时也会使用全局变量和静态变量,如果多线程随意同时访问全局变量和静态变量,就将出现意向不到的错误,这个在现在的多线程编程中一般都会通过加锁等机制解决,但我们往往忽略了C run-time library里面的一些函数使用了全局变量和静态变量却没用相应机制避免冲突。

而readdir函数因为内部使用了静态数据,即readdir成功时返回指针所指向的dirent结构体是静态分配的,所以readdir被认为不是线程安全的函数,POSIX[i]标准这样描述:

         The application shall not modify the structure to which the return value of readdir() points, nor any storage areas pointed to by pointers within the structure. The returned pointer, and pointers within the structure, might be invalidated or the structure or the storage areas might be overwritten by a subsequent call to readdir() on the same directory stream. They shall not be affected by a call to readdir() on a different directory stream.

         If a file is removed from or added to the directory after the most recent call to opendir() or rewinddir(),whether a subsequent call to readdir() returns an entry for that file is unspecified.

         The readdir() function need not be thread-safe.

解决方法可以采用局部变量保存数据,也可以加锁使用;当然还可以使用readdir_r函数(然而,在GNU的官方文档[ii]中还是建议使用readdir函数)。

 

`direntp` 通常指的是在操作目录时使用的 `struct dirent` 结构体指针。`readdir` 函数在读取目录时会返回一个指向 `struct dirent` 的指针,而这个操作是线程安全的,以下是具体原因及解决方案: ### 原因 `readdir` 函数线程安全的,因为它使用了一个静态分配的缓冲区来存储 `struct dirent` 信息。这意味着在多线程环境中,多个线程可能会同时调用 `readdir` 函数,而这些调用会共享同一个静态缓冲区。当一个线程正在读取目录条目并更新这个缓冲区时,另一个线程可能会同时尝试访问或修改这个缓冲区,从而导致数据混乱和可预测的结果。 下面是一个简单的示例代码,展示了这种情况可能出现的问题: ```c #include <stdio.h> #include <dirent.h> #include <pthread.h> void *read_directory(void *arg) { DIR *dir = opendir("."); if (dir == NULL) { perror("opendir"); return NULL; } struct dirent *entry; while ((entry = readdir(dir)) != NULL) { printf("Thread %ld: %s\n", (long)arg, entry->d_name); } closedir(dir); return NULL; } int main() { pthread_t threads[2]; for (long i = 0; i < 2; i++) { pthread_create(&threads[i], NULL, read_directory, (void *)i); } for (int i = 0; i < 2; i++) { pthread_join(threads[i], NULL); } return 0; } ``` 在这个示例中,两个线程同时调用 `readdir` 函数,可能会导致输出的目录条目混乱。 ### 解决方案 1. **使用线程同步机制**:可以使用互斥锁(`pthread_mutex_t`)来确保同一时间只有一个线程可以调用 `readdir` 函数。以下是修改后的代码示例: ```c #include <stdio.h> #include <dirent.h> #include <pthread.h> pthread_mutex_t mutex; void *read_directory(void *arg) { DIR *dir = opendir("."); if (dir == NULL) { perror("opendir"); return NULL; } struct dirent *entry; while (1) { pthread_mutex_lock(&mutex); entry = readdir(dir); pthread_mutex_unlock(&mutex); if (entry == NULL) { break; } printf("Thread %ld: %s\n", (long)arg, entry->d_name); } closedir(dir); return NULL; } int main() { pthread_t threads[2]; pthread_mutex_init(&mutex, NULL); for (long i = 0; i < 2; i++) { pthread_create(&threads[i], NULL, read_directory, (void *)i); } for (int i = 0; i < 2; i++) { pthread_join(threads[i], NULL); } pthread_mutex_destroy(&mutex); return 0; } ``` 在这个示例中,使用了互斥锁来确保同一时间只有一个线程可以调用 `readdir` 函数,从而避免了数据混乱的问题。 2. **使用线程安全函数**:许多系统提供了线程安全版本的 `readdir` 函数,如 `readdir_r`。这个函数接受一个额外的参数,用于指定一个用户提供的缓冲区,从而避免了使用静态缓冲区的问题。以下是使用 `readdir_r` 的示例代码: ```c #include <stdio.h> #include <dirent.h> #include <pthread.h> void *read_directory(void *arg) { DIR *dir = opendir("."); if (dir == NULL) { perror("opendir"); return NULL; } struct dirent entry; struct dirent *result; while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { printf("Thread %ld: %s\n", (long)arg, entry.d_name); } closedir(dir); return NULL; } int main() { pthread_t threads[2]; for (long i = 0; i < 2; i++) { pthread_create(&threads[i], NULL, read_directory, (void *)i); } for (int i = 0; i < 2; i++) { pthread_join(threads[i], NULL); } return 0; } ``` 在这个示例中,使用了 `readdir_r` 函数,它会将目录条目信息存储在用户提供的 `struct dirent` 结构体中,从而避免了多线程之间的冲突。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值