1. 使用内存映射技术实现多进程并发访问文件不同区域
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#define FILE_SIZE 1024 * 1024 // 假设文件大小为1MB
#define PROCESS_NUM 4
// 用于进程间同步的信号量
sem_t *semaphore;
void handle_error(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
void process_task(int start, int length) {
int fd = open("large_file", O_RDWR);
if (fd == -1) {
handle_error("open");
}
// 映射文件到内存
char *file_map = (char *)mmap(NULL, FILE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (file_map == MAP_FAILED) {
handle_error("mmap");
}
// 等待信号量,避免数据竞争
if (sem_wait(semaphore) == -1) {
handle_error("sem_wait");
}
// 处理文件特定区域的数据
for (int i = start; i < start + length; i++) {
file_map[i] = file_map[i] + 1; // 简单的数据处理示例
}
// 释放信号量
if (sem_post(semaphore) == -1) {
handle_error("sem_post");
}
// 解除映射
if (munmap(file_map, FILE_SIZE) == -1) {
handle_error("munmap");
}
close(fd);
}
int main() {
// 创建大文件并初始化内容
int fd = open("large_file", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
handle_error("open");
}
if (lseek(fd, FILE_SIZE - 1, SEEK_SET) == -1) {
handle_error("lseek");
}
if (write(fd, "", 1) != 1) {
handle_error("write");
}
close(fd);
// 创建信号量用于同步
semaphore = sem_open("/my_semaphore", O_CREAT, 0644, 1);
if (semaphore == SEM_FAILED) {
handle_error("sem_open");
}
// 创建子进程并发处理文件不同区域
for (int i = 0; i < PROCESS_NUM; i++) {
pid_t pid = fork();
if (pid == -1) {
handle_error("fork");
} else if (pid == 0) {
int start = i * (FILE_SIZE / PROCESS_NUM);
int length = FILE_SIZE / PROCESS_NUM;
process_task(start, length);
exit(EXIT_SUCCESS);
}
}
// 等待所有子进程结束
for (int i = 0; i < PROCESS_NUM; i++) {
wait(NULL);
}
// 删除信号量
if (sem_close(semaphore) == -1) {
handle_error("sem_close");
}
if (sem_unlink("/my_semaphore") == -1) {
handle_error("sem_unlink");
}
return 0;
}
2. 避免进程间数据竞争的方法
- 信号量(Semaphore):在上述代码中,使用
semaphore
来控制对共享内存区域的访问。每个进程在访问共享内存前,先通过sem_wait
获取信号量,处理完数据后通过sem_post
释放信号量。这样同一时间只有一个进程可以访问共享内存,避免了数据竞争。
- 互斥锁(Mutex):互斥锁本质上是一种特殊的二值信号量(取值为0或1)。可以使用
pthread_mutex_t
类型的互斥锁,在进程间通过共享内存的方式来使用。在访问共享内存前加锁(pthread_mutex_lock
),访问结束后解锁(pthread_mutex_unlock
)。
3. 优化性能的方法
- 减少锁的粒度:如果可能,将共享内存划分成更小的部分,每个进程只对自己需要的部分加锁。这样可以允许更多的进程同时访问不同部分的共享内存,提高并发性能。
- 预读取:在处理数据前,提前将需要的数据从磁盘读取到内存中,减少I/O等待时间。可以使用
posix_fadvise
函数来向系统建议文件的访问模式,例如POSIX_FADV_SEQUENTIAL
表示顺序访问,POSIX_FADV_RANDOM
表示随机访问,帮助系统优化I/O。
- 多线程处理:除了多进程,还可以结合多线程。在每个进程内部使用多线程来进一步提高并发度。但需要注意线程间同样存在数据竞争问题,需要使用线程同步机制(如互斥锁、条件变量等)。
- 异步I/O:使用异步I/O函数(如
aio_read
、aio_write
),在进行I/O操作时不会阻塞主线程,从而提高程序的整体性能。