避免文件描述符资源泄露
- 及时关闭文件描述符:在使用完文件描述符后,无论是成功完成操作还是在操作过程中出现错误,都要确保调用
close()
函数关闭文件描述符。例如:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("test.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
// 进行文件操作
close(fd);
return 0;
}
- 使用
atexit
函数:可以注册一个函数,在程序正常退出时自动关闭所有打开的文件描述符。例如:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int fd1, fd2;
void close_files() {
close(fd1);
close(fd2);
}
int main() {
fd1 = open("file1.txt", O_RDONLY);
fd2 = open("file2.txt", O_RDONLY);
if (fd1 == -1 || fd2 == -1) {
perror("open");
if (fd1 != -1) close(fd1);
if (fd2 != -1) close(fd2);
return 1;
}
atexit(close_files);
// 进行文件操作
return 0;
}
- 利用RAII思想(手动模拟):定义一个结构体来管理文件描述符,在结构体的析构函数(自定义的清理函数)中关闭文件描述符。例如:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct {
int fd;
} FileDescriptor;
void FileDescriptor_init(FileDescriptor *fd_obj, const char *filename, int flags) {
fd_obj->fd = open(filename, flags);
if (fd_obj->fd == -1) {
perror("open");
exit(1);
}
}
void FileDescriptor_destroy(FileDescriptor *fd_obj) {
close(fd_obj->fd);
}
int main() {
FileDescriptor fd1, fd2;
FileDescriptor_init(&fd1, "file1.txt", O_RDONLY);
FileDescriptor_init(&fd2, "file2.txt", O_RDONLY);
// 进行文件操作
FileDescriptor_destroy(&fd1);
FileDescriptor_destroy(&fd2);
return 0;
}
多文件异步I/O操作的同步和错误处理
- 同步机制
- 互斥锁(
pthread_mutex_t
):如果需要对共享资源(如文件元数据)进行保护,可以使用互斥锁。例如,在更新文件的某些共享状态时:
#include <pthread.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
pthread_mutex_t mutex;
int global_file_status;
void *async_io_thread(void *arg) {
int fd = *(int *)arg;
pthread_mutex_lock(&mutex);
// 访问或修改共享资源 global_file_status
pthread_mutex_unlock(&mutex);
// 进行异步I/O操作
return NULL;
}
int main() {
pthread_mutex_init(&mutex, NULL);
int fd1 = open("file1.txt", O_RDONLY);
int fd2 = open("file2.txt", O_RDONLY);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, async_io_thread, &fd1);
pthread_create(&tid2, NULL, async_io_thread, &fd2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_mutex_destroy(&mutex);
close(fd1);
close(fd2);
return 0;
}
- **信号量(`sem_t`)**:可以用于控制同时访问文件的线程或进程数量。例如,限制最多有3个异步I/O操作同时进行:
#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
sem_t semaphore;
void *async_io_thread(void *arg) {
int fd = *(int *)arg;
sem_wait(&semaphore);
// 进行异步I/O操作
sem_post(&semaphore);
return NULL;
}
int main() {
sem_init(&semaphore, 0, 3);
int fd1 = open("file1.txt", O_RDONLY);
int fd2 = open("file2.txt", O_RDONLY);
int fd3 = open("file3.txt", O_RDONLY);
int fd4 = open("file4.txt", O_RDONLY);
pthread_t tid1, tid2, tid3, tid4;
pthread_create(&tid1, NULL, async_io_thread, &fd1);
pthread_create(&tid2, NULL, async_io_thread, &fd2);
pthread_create(&tid3, NULL, async_io_thread, &fd3);
pthread_create(&tid4, NULL, async_io_thread, &fd4);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_join(tid4, NULL);
sem_destroy(&semaphore);
close(fd1);
close(fd2);
close(fd3);
close(fd4);
return 0;
}
- 错误处理
- 检查系统调用返回值:每次进行异步I/O相关的系统调用(如
aio_read
、aio_write
)后,检查其返回值。如果返回值表示错误,使用errno
获取具体的错误代码,并进行相应处理。例如:
#include <aio.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("test.txt", O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
struct aiocb aiocbp;
// 初始化 aiocbp
int res = aio_read(&aiocbp);
if (res == -1) {
perror("aio_read");
close(fd);
return 1;
}
// 等待操作完成并检查结果
res = aio_suspend(&aiocbp, 1, NULL);
if (res == -1) {
perror("aio_suspend");
close(fd);
return 1;
}
int status = aio_return(&aiocbp);
if (status == -1) {
perror("aio_return");
close(fd);
return 1;
}
close(fd);
return 0;
}
- **错误日志记录**:使用`syslog`或自定义的日志函数记录错误信息,以便于调试和排查问题。例如:
#include <syslog.h>
#include <aio.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
openlog("async_io_app", LOG_PID, LOG_USER);
int fd = open("test.txt", O_RDONLY);
if (fd == -1) {
syslog(LOG_ERR, "open failed: %m");
return 1;
}
struct aiocb aiocbp;
// 初始化 aiocbp
int res = aio_read(&aiocbp);
if (res == -1) {
syslog(LOG_ERR, "aio_read failed: %m");
close(fd);
return 1;
}
// 等待操作完成并检查结果
res = aio_suspend(&aiocbp, 1, NULL);
if (res == -1) {
syslog(LOG_ERR, "aio_suspend failed: %m");
close(fd);
return 1;
}
int status = aio_return(&aiocbp);
if (status == -1) {
syslog(LOG_ERR, "aio_return failed: %m");
close(fd);
return 1;
}
close(fd);
closelog();
return 0;
}