Bản đồ bộ nhớ
Lệnh gọi hệ thống mmap () cung cấp ánh xạ trong không gian địa chỉ ảo của quá trình gọi ánh xạ các tệp hoặc thiết bị vào bộ nhớ. Đây là hai loại -
File mapping or File-backed mapping- Ánh xạ này ánh xạ vùng của bộ nhớ ảo của tiến trình với các tệp. Điều này có nghĩa là việc đọc hoặc ghi vào những vùng bộ nhớ đó khiến tệp được đọc hoặc ghi. Đây là kiểu ánh xạ mặc định.
Anonymous mapping- Ánh xạ này ánh xạ khu vực của bộ nhớ ảo của tiến trình mà không cần bất kỳ tệp nào hỗ trợ. Nội dung được khởi tạo bằng 0. Ánh xạ này tương tự như cấp phát bộ nhớ động (malloc ()) và được sử dụng trong một số triển khai malloc () cho một số cấp phát nhất định.
Bộ nhớ trong một ánh xạ quy trình có thể được chia sẻ với ánh xạ trong các quy trình khác. Điều này có thể được thực hiện theo hai cách -
Khi hai quá trình ánh xạ cùng một vùng của một tệp, chúng chia sẻ các trang của bộ nhớ vật lý giống nhau.
Nếu một tiến trình con được tạo ra, nó sẽ kế thừa các ánh xạ của cha và các ánh xạ này tham chiếu đến các trang của bộ nhớ vật lý giống như của cha. Khi có bất kỳ thay đổi nào về dữ liệu trong quy trình con, các trang khác nhau sẽ được tạo cho quy trình con.
Khi hai hoặc nhiều quy trình chia sẻ các trang giống nhau, mỗi quy trình có thể thấy các thay đổi của nội dung trang do các quy trình khác thực hiện tùy thuộc vào loại ánh xạ. Loại ánh xạ có thể là riêng tư hoặc được chia sẻ -
Private Mapping (MAP_PRIVATE) - Các sửa đổi đối với nội dung của ánh xạ này không hiển thị đối với các quy trình khác và ánh xạ không được chuyển đến tệp bên dưới.
Shared Mapping (MAP_SHARED) - Các sửa đổi đối với nội dung của ánh xạ này có thể nhìn thấy đối với các quá trình khác và ánh xạ được chuyển đến tệp bên dưới.
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
Lệnh gọi hệ thống ở trên trả về địa chỉ bắt đầu của ánh xạ khi thành công hoặc MAP_FAILED do lỗi.
Trình bổ sung địa chỉ ảo, có thể được người dùng chỉ định hoặc được tạo bởi hạt nhân (khi chuyển trình bổ sung dưới dạng NULL). Độ dài trường được chỉ ra yêu cầu kích thước ánh xạ theo byte. Trường prot chỉ ra các giá trị bảo vệ bộ nhớ như PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC dành cho các vùng có thể không được truy cập, đọc, ghi hoặc thực thi tương ứng. Giá trị này có thể là đơn (PROT_NONE) hoặc có thể là ORd với bất kỳ cờ nào trong ba cờ (3 cuối). Các cờ trường cho biết loại ánh xạ hoặc MAP_PRIVATE hoặc MAP_SHARED. Trường 'fd' cho biết bộ mô tả tệp xác định tệp sẽ được ánh xạ và trường "offset" ngụ ý điểm bắt đầu của tệp, nếu cần ánh xạ toàn bộ tệp, độ lệch phải bằng không.
#include <sys/mman.h>
int munmap(void *addr, size_t length);
Lệnh gọi hệ thống ở trên trả về 0 nếu thành công hoặc -1 khi lỗi.
Hệ thống gọi munmap, thực hiện việc giải nén vùng bộ nhớ đã được ánh xạ. Các trường bổ sung cho biết địa chỉ bắt đầu của ánh xạ và chiều dài cho biết kích thước tính bằng byte của ánh xạ sẽ được bỏ ánh xạ. Thông thường, ánh xạ và bỏ ánh xạ sẽ dành cho toàn bộ các vùng được ánh xạ. Nếu điều này phải khác, thì nó nên được thu nhỏ hoặc cắt làm hai phần. Nếu trình bổ sung không có bất kỳ ánh xạ nào thì cuộc gọi này sẽ không có hiệu lực và cuộc gọi trả về 0 (thành công).
Hãy để chúng tôi xem xét một ví dụ -
Step 1 - Đánh dấu vào tệp ký tự Alpha Numeric như hình bên dưới -
0 | 1 | 2 | … | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | … | 59 | 60 | 61 |
A | B | C | … | Z | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | b | c | … | x | y | z |
Step 2- Ánh xạ nội dung tệp vào bộ nhớ bằng lệnh gọi hệ thống mmap (). Điều này sẽ trả về địa chỉ bắt đầu sau khi ánh xạ vào bộ nhớ.
Step 3- Truy cập nội dung tệp bằng ký hiệu mảng (cũng có thể truy cập bằng ký hiệu con trỏ) vì không đọc lệnh gọi hệ thống read () đắt tiền. Sử dụng ánh xạ bộ nhớ, tránh sao chép nhiều lần giữa không gian người dùng, bộ đệm không gian nhân và bộ đệm đệm.
Step 4 - Lặp lại việc đọc nội dung tệp cho đến khi người dùng nhập “-1” (có nghĩa là kết thúc truy cập).
Step 5 - Thực hiện các hoạt động dọn dẹp tức là giải nén vùng bộ nhớ được ánh xạ (munmap ()), đóng tệp và xóa tệp.
/* Filename: mmap_test.c */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
void write_mmap_sample_data();
int main() {
struct stat mmapstat;
char *data;
int minbyteindex;
int maxbyteindex;
int offset;
int fd;
int unmapstatus;
write_mmap_sample_data();
if (stat("MMAP_DATA.txt", &mmapstat) == -1) {
perror("stat failure");
return 1;
}
if ((fd = open("MMAP_DATA.txt", O_RDONLY)) == -1) {
perror("open failure");
return 1;
}
data = mmap((caddr_t)0, mmapstat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (data == (caddr_t)(-1)) {
perror("mmap failure");
return 1;
}
minbyteindex = 0;
maxbyteindex = mmapstat.st_size - 1;
do {
printf("Enter -1 to quit or ");
printf("enter a number between %d and %d: ", minbyteindex, maxbyteindex);
scanf("%d",&offset);
if ( (offset >= 0) && (offset <= maxbyteindex) )
printf("Received char at %d is %c\n", offset, data[offset]);
else if (offset != -1)
printf("Received invalid index %d\n", offset);
} while (offset != -1);
unmapstatus = munmap(data, mmapstat.st_size);
if (unmapstatus == -1) {
perror("munmap failure");
return 1;
}
close(fd);
system("rm -f MMAP_DATA.txt");
return 0;
}
void write_mmap_sample_data() {
int fd;
char ch;
struct stat textfilestat;
fd = open("MMAP_DATA.txt", O_CREAT|O_TRUNC|O_WRONLY, 0666);
if (fd == -1) {
perror("File open error ");
return;
}
// Write A to Z
ch = 'A';
while (ch <= 'Z') {
write(fd, &ch, sizeof(ch));
ch++;
}
// Write 0 to 9
ch = '0';
while (ch <= '9') {
write(fd, &ch, sizeof(ch));
ch++;
}
// Write a to z
ch = 'a';
while (ch <= 'z') {
write(fd, &ch, sizeof(ch));
ch++;
}
close(fd);
return;
}
Đầu ra
Enter -1 to quit or enter a number between 0 and 61: 3
Received char at 3 is D
Enter -1 to quit or enter a number between 0 and 61: 28
Received char at 28 is 2
Enter -1 to quit or enter a number between 0 and 61: 38
Received char at 38 is c
Enter -1 to quit or enter a number between 0 and 61: 59
Received char at 59 is x
Enter -1 to quit or enter a number between 0 and 61: 65
Received invalid index 65
Enter -1 to quit or enter a number between 0 and 61: -99
Received invalid index -99
Enter -1 to quit or enter a number between 0 and 61: -1