shmat permission denied 的解决方法

解决共享内存权限问题

进程间可以通过shmget/shmat等一系列函数共享内存。

参照这些博客,我们可以实现:

http://nnssll.blog.51cto.com/902724/199808(原文有错,注意看评论)

http://wellwy.blog.51cto.com/1609602/492083

不过在尝试过程中遇到了一些困难:

shm_addr=(char*)shmat(shm_id,NULL,0); 返回-1。

perror 打印出:permission denied

查看了网上的一些资料,说是要shmget的时候要加上0666权限,比如:

shm_id=shmget(key,4096,IPC_CREAT|0666);

但是还是不行。

后来想到ftok的时候用到了一个filepath

key=ftok(filepath,0);

这个ftok必须是已存在真实文件,是不是文件的权限问题?

用chmod 777 filepath之后果然可以了。。。

如果还不行的话可以有sudo运行程序试一下。


#include <stdio.h> #include <sys/sem.h> #include <sys/shm.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <signal.h> // ✅ 新增:用于 SIGTERM #define SHMKEY_BASE 1024 // 共享内存基 key #define SEMKEY 2048 // 信号量 key #define DATASIZE 256 // 每个缓冲区的数据 int 数量 #define BUFFERNUM 10 // 缓冲区个数 #define BLOCK_SIZE (DATASIZE * sizeof(int)) // 实际字节数 // 共享缓冲区结构 typedef struct ShareBuffer { int data_size; // 实际写入的字节数 int data[DATASIZE]; // 数据区(总共 BLOCK_SIZE 字节) } ShareBuffer; // ✅ 全局变量声明必须放在所有函数之前! int sid; // 信号量 ID int shmid[BUFFERNUM]; // 共享内存 ID 数组 ← 必须提前声明! // 信号量操作封装 void P(int semid, int index) { struct sembuf sb = {index, -1, 0}; semop(semid, &sb, 1); } void V(int semid, int index) { struct sembuf sb = {index, 1, 0}; semop(semid, &sb, 1); } void printHelp() { fprintf(stderr, "Usage: %s <source_file> <dest_file>\n", "a.out"); } // 生产者:读文件入共享内存 void read_buf(int src_fd) { ShareBuffer* buffers[BUFFERNUM]; // 一次性 attach 所有共享内存 for (int i = 0; i < BUFFERNUM; ++i) { buffers[i] = (ShareBuffer*)shmat(shmid[i], NULL, 0); if (buffers[i] == (void*)-1) { perror("shmat in reader"); exit(1); } } int j = 0; ssize_t n; while ((n = read(src_fd, buffers[j]->data, BLOCK_SIZE)) > 0) { // ✅ 使用 -> 而不是 . P(sid, 2); // 请求一个空缓冲区 P(sid, 0); // 获取互斥锁 printf("Reading block %d: %ld bytes\n", j, n); buffers[j]->data_size = n; // ✅ 正确:使用 -> 访问指针成员 V(sid, 0); // 释放互斥锁 V(sid, 1); // 增加满缓冲区计数 j = (j + 1) % BUFFERNUM; } if (n < 0) { perror("read error"); } // 标记结束:最后一个块 data_size 设为 0 P(sid, 2); P(sid, 0); buffers[j]->data_size = 0; // 终止标志 V(sid, 0); V(sid, 1); close(src_fd); for (int i = 0; i < BUFFERNUM; ++i) shmdt(buffers[i]); // 解除映射 exit(0); } // 消费者:从共享内存写文件 void write_buf(int dst_fd) { ShareBuffer* buffers[BUFFERNUM]; // attach 所有共享内存 for (int i = 0; i < BUFFERNUM; ++i) { buffers[i] = (ShareBuffer*)shmat(shmid[i], NULL, 0); if (buffers[i] == (void*)-1) { perror("shmat in writer"); exit(1); } } int j = 0; while (1) { P(sid, 1); // 等待一个满缓冲区 P(sid, 0); // 获取互斥锁 int size = buffers[j]->data_size; if (size == 0) { // 收到终止信号 V(sid, 0); // 释放锁 V(sid, 2); // 归还空槽 break; } printf("Writing block %d: %d bytes\n", j, size); if (write(dst_fd, buffers[j]->data, size) != size) { perror("write error"); break; } V(sid, 0); // 释放互斥锁 V(sid, 2); // 空缓冲区+1 j = (j + 1) % BUFFERNUM; } close(dst_fd); for (int i = 0; i < BUFFERNUM; ++i) shmdt(buffers[i]); exit(0); } int main(int argc, char* argv[]) { if (argc != 3) { fprintf(stderr, "参数错误!\n"); printHelp(); return 1; } // 打开原始文件(使用系统调用) int src_fd = open(argv[1], O_RDONLY); if (src_fd < 0) { perror("无法打开源文件"); return 1; } int dst_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); if (dst_fd < 0) { perror("无法创建目标文件"); close(src_fd); return 1; } // 创建信号量集(3个) sid = semget((key_t)SEMKEY, 3, IPC_CREAT | 0666); if (sid == -1) { perror("semget failed"); close(src_fd); close(dst_fd); return 1; } // 初始化信号量 semctl(sid, 0, SETVAL, 1); // mutex = 1 semctl(sid, 1, SETVAL, 0); // full = 0 semctl(sid, 2, SETVAL, BUFFERNUM); // empty = BUFFERNUM // 创建共享内存段 for (int i = 0; i < BUFFERNUM; ++i) { shmid[i] = shmget((SHMKEY_BASE + i), sizeof(ShareBuffer), IPC_CREAT | 0666); if (shmid[i] == -1) { perror("shmget failed"); // 清理已创建的资源 for (int k = 0; k < i; ++k) shmctl(shmid[k], IPC_RMID, NULL); semctl(sid, 0, IPC_RMID); return 1; } } // 创建两个子进程 pid_t p1 = fork(); if (p1 == 0) { read_buf(src_fd); // 子进程执行读取 } else if (p1 < 0) { perror("fork reader failed"); return 1; } pid_t p2 = fork(); if (p2 == 0) { write_buf(dst_fd); // 子进程执行写入 } else if (p2 < 0) { perror("fork writer failed"); kill(p1, SIGTERM); // ✅ 现在可用:因为包含了 <signal.h> return 1; } // 父进程等待 waitpid(p1, NULL, 0); waitpid(p2, NULL, 0); // 清理资源 semctl(sid, 0, IPC_RMID); // 删除信号量集 for (int i = 0; i < BUFFERNUM; ++i) { shmctl(shmid[i], IPC_RMID, NULL); // 删除共享内存 } printf("文件复制完成。\n"); return 0; } 怎么运行
最新发布
11-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值