信号量和共享内存简单实例练习:共享内存是所有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.