gpt4 book ai didi

c - dlclose 不关闭库打开的文件句柄

转载 作者:太空狗 更新时间:2023-10-29 17:22:03 24 4
gpt4 key购买 nike

我正在使用 dlopen 动态加载库,然后使用 dlclose 关闭它。我希望在 dlclose 完成后释放所有库资源,但在 dlclose 调用之后,库中仍有打开的文件描述符。我想知道如何确保在程序执行过程中卸载库,以便清理所有资源。

我的代码如下:

#include <CL/cl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dlfcn.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>

#define MAX_PATH_LENGTH 80

int deviceQ()
{
cl_int ret;
void * libHandle = dlopen("/usr/lib64/libOpenCL.so", RTLD_LAZY);
cl_int (* clGetPlatformIDs)(cl_uint, cl_platform_id*, cl_uint*) = dlsym(
libHandle, "clGetPlatformIDs"
);
cl_int (* clGetDeviceIDs)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*) =
dlsym(libHandle, "clGetDeviceIDs");
/********************** PREAMBLE **************************************/
cl_device_id device_id = NULL;
cl_platform_id platform_id = NULL;
cl_uint ret_num_devices;
cl_uint ret_num_platforms;

ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
if (ret != CL_SUCCESS) {
perror("Failed to get platform IDs");
} else if (ret_num_platforms != 1) {
fprintf(stderr, "Number of platforms returned is %d\n", ret_num_platforms);
exit(1);
}

printf("Read platform IDs\n");

ret = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id,
&ret_num_devices);
if (ret != CL_SUCCESS) {
perror("Failed to get device IDs");
} else if (ret_num_devices != 1) {
fprintf(stderr, "Number of returned devices is %d\n", ret_num_devices);
exit(1);
}
printf("Read device IDs\n");
/********************** PREAMBLE **************************************/

/***************** RELEASE AND FREE ****************************/
dlclose(libHandle);
/***************** RELEASE AND FREE ****************************/

return 0;
}

size_t closeFileDescriptors(void ** arr) {
// step 1 - get PID
pid_t pid = getpid();
//printf("PID is %d\n", pid);

char path[MAX_PATH_LENGTH];
memset(path, '\0', MAX_PATH_LENGTH);
sprintf(path, "/proc/%d/fd", pid);

int fd;
DIR * d = opendir(path);
struct dirent *dir;
struct stat s;
char dirPath[MAX_PATH_LENGTH];
char realPath[MAX_PATH_LENGTH];

size_t index = 0;

if (d) {
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") != 0 &&
strcmp(dir->d_name, "..") != 0) {
fd = atoi(dir->d_name);

if (fstat(fd, &s) != 0) {
perror("fstat failed");
}
memset(dirPath, '\0', MAX_PATH_LENGTH);
strcpy(dirPath, path);
strcat(dirPath, "/");
strcat(dirPath, dir->d_name);

#ifdef S_IFLNK
if (s.st_mode & S_IFLNK) {
#else
if (S_ISLNK(s.st_mode)) {
#endif
memset(realPath, '\0', MAX_PATH_LENGTH);
#ifdef readlink
readlink(dirPath, realPath, MAX_PATH_LENGTH);
printf("%s -> %s\n", dirPath, realPath);
#else
printf("[readlink not defined] %s\n", dirPath);
#endif
} else {
printf("Not link: %s (proceeding anyway)\n", dirPath);
//printf("Not link: %s (ignoring)\n", dirPath);
//continue;
}

if (fd > 2) {
//int fdFlags = fcntl(fd, F_GETFD);
int fdFlags = fcntl(fd, F_GETFL);
if (fdFlags == -1) {
perror("fcntl failed");
}
//off_t offset = lseek(fd, 0, SEEK_CUR);
off_t offset = 0;
if (offset == -1) {
perror("lseek failed");
}
if (arr != NULL) {
/*
arr[index] = (fileData *) malloc(sizeof (fileData));
arr[index]->flags = fdFlags;
arr[index]->offset = offset;
arr[index]->fd = fd;
strcpy(arr[index]->fdPath, realPath);*/
}
index++;

// ignore stdin, stdout, stderr
printf("Closing FD %d (flags %d, offset %zd)\n",
fd, fdFlags, offset);
close(fd);
}
}
}
closedir(d);
} else {
fprintf(stderr, "Could not open directory %s\n", path);
}
return index;
}

int main () {
deviceQ();

printf("=> Closing open file descriptors\n");
closeFileDescriptors (NULL);

deviceQ();
return 0;
}

最佳答案

你的期望是错误的。当您调用 dlclose(3) 时,只有“插件”(实际上是共享对象)被“关闭”(实际上,可能是 munmap-ed),但不是资源(特别是它使用的文件描述符,可能还有堆分配的内存)。

此外,特别是在 Linux 上,dlclose 正在调用插件的所谓析构函数(那些用 __attribute__((destructor)) 声明的函数,阅读 function attributes在 GCC 中)。

如果您正在编写一个共享库,您可以将其设计为在dlclose 时间释放一些 资源(通过析构函数运行适当的终结 函数)。一般来说,这不容易实现(并且应该是一个记录在案的约定)。

虚拟内存中的地址空间(由 mmap(2) 等获得)和文件描述符(由 open(2)socket(2)pipe(2) 等获得)等资源对于整个 process 是全局的(和公共(public)的)。因此,在一个共享库中获取一些资源(例如打开一些文件描述符)并在另一个共享库(或在主程序中)释放它是可能的(并且是合法的,如果有记录的话)。

由于资源“属于”整个过程,所以说释放图书馆获得的资源是没有意义的。

所以您的 closeFileDescriptors 很可能是一个巨大的错误(并且它可能泄漏了一些其他资源)。

(IIRC,OpenCL API 有一些方法来释放它的资源,例如设备、上下文、内核等....但我忘记了丑陋的细节;参见clReleaseContext clReleaseMemObject 等等,包括一些特定于实现的对象。)

阅读更多关于 garbage collection 的内容可能会拓宽您的思路。

另请阅读 Drepper 的论文:How To Write a Shared Librarycredentials(7)

如果您绝对需要尽早释放 OpenCL 相关资源,更明智的方法可能是启动一个专用于 OpenCL 事物的不同子进程,并使用巧妙的 IPC 机制(例如 pipe(7)shm_overview(7)sem_overview(7) 等...)然后一旦您的 OpenCL 工作完成,就(正确地)终止该子进程。您利用了内核正在清除已失效进程使用的所有资源这一事实(不要忘记 wait...它 - 例如使用 waitpid(2) - 以避免拥有 zombie processes )。如果您不熟悉所有内容,请先阅读 Advanced Linux Programming

关于c - dlclose 不关闭库打开的文件句柄,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30945894/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com