信號量和共享內存簡單實例練習:共享內存是所有IPC中最快的,但是需要某種形式的進程同步策略,通常選用信號量進行同步。
// 文件創建訪問權限
#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
int main(int argc, char *argv[])
{
int fd = -1;
char* ptr = nullptr;
sem_t* sem_ = nullptr;
char zero_buffer[4096] = { 0 };
fd = open("test", O_RDWR | O_CREAT, RWRWRW);
assert(-1 != fd);
// 這一步注意,要映射多大空間,源文件就需要有多大尺寸,否則mmap的時候空間會小於指定大小
write(fd, zero_buffer, 4096);
// 上一步打開文件的操作可以省略,指定flag | MAP_ANON,並且將fd設置爲-1即可, 此時offset參數會被忽略
// 創建映射文件區
ptr = (char *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
assert(nullptr != ptr);
// 關閉文件描述符
close(fd);
// 有名信號量
sem_ = sem_open("sem_file", O_CREAT | O_EXCL, RWRWRW, 1);
assert(nullptr != sem_);
// 刪除與信號量關聯的輔助文件
sem_unlink("sem_file");
if (0 == fork()) { // 子進程讀
while (1) {
sem_wait(sem_);
printf("child: %s\n", ptr);
sem_post(sem_);
sleep(1);
}
return 0;
}
// 父進程寫
while (1) {
sem_wait(sem_);
memset(ptr, 0, 4096);
strcat(ptr, "this is mmap test.");
sem_post(sem_);
sleep(1);
}
return 0;
}
基於內存的信號量(無名信號量):
// 文件創建訪問權限
#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
int main()
{
int fd = -1;
char* ptr = nullptr;
sem_t sem_;
char zero_buffer[4096] = { 0 };
fd = open("test", O_RDWR | O_CREAT, RWRWRW);
assert(-1 != fd);
write(fd, zero_buffer, 4096);
// 創建映射文件區
ptr = (char *)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
assert(nullptr != ptr);
// 關閉文件描述符
close(fd);
// 無名信號量
sem_init(&sem_, 1, 1);
if (0 == fork()) { // 子進程讀
while (1) {
sem_wait(&sem_);
printf("child: %s\n", ptr);
sem_post(&sem_);
sleep(1);
}
return 0;
}
// 父進程寫
while (1) {
sem_wait(&sem_);
memset(ptr, 0, 4096);
strcat(ptr, "this is mmap test.");
sem_post(&sem_);
sleep(1);
}
return 0;
}
這裏還需要注意一點是:
SIGSEGV和SIGBUS的引發錯誤的區別:
SIGBUS意味着任然在內存映射區內訪問,但是超出了底層支撐對象的大小。
SIGSEGV意味着我們已經在映射區以外訪問。
另外:映射區分配是以頁面大小整數倍分配的,如果頁面大小爲4096,那麼mmapsize = 5000時實際分配的映射區大小向上取整爲8096.