``` g_shmid = shmget(key, sizeof(struct share_mem_data), IPC_CREAT | 0666) ```
时间: 2024-09-12 14:15:18 浏览: 49
这段代码是在C语言中使用POSIX线程库(pthread)操作共享内存(Shared Memory)。其中:
- `g_shmid`:是一个存储共享内存ID(Shmem ID)的变量,它将被用来管理创建的共享内存区域。
- `shmget(key, sizeof(struct share_mem_data), IPC_CREAT | 0666)` 是对`shmat`函数的一个前奏,用于创建共享内存块:
- `key`:这是之前通过`ftok`函数得到的标识符,用于查找或创建具有特定名称的共享内存区域。如果`key`已经存在,则会被重新获取;如果不存在,会根据提供的权限创建一个新的。
- `sizeof(struct share_mem_data)`:这是指定要创建的共享内存大小,等于`struct share_mem_data`数据类型占用的空间。
- `IPC_CREAT`:这是一个标志位,表示如果没有找到与给定键匹配的已存在的共享内存,就创建一个新的。
- `0666`:这是权限模式,使用八进制表示,`0666`意味着所有用户都有读写权限。在实际项目中,可能需要根据安全需求进行调整。
这行代码的主要作用是尝试创建一个共享内存区域,并且如果需要的话,允许创建新的(即当键不存在时)。成功创建后,`g_shmid`会保存这个新共享内存的ID,以便后续使用`shmat`函数将其映射到当前进程的地址空间。
相关问题
此应用程序执行到最后会出现错误提示“trying to free free page”,这是由于sys_shmget函数在 使用get_free_page函数申请到一个物理页时,将此物理页在mem_map中记录的引用计数设置为1,而再次调 用sys_shmget函数使用key从vector中获取共享的物理页时,没有增加此物理页在mem_map中的引用计数。 所以,当生产者进程和消费者进程退出时,都会调用free_page函数释放此物理页,每调用一次就会将 mem_map中的引用计数减1,导致一个物理页的引用计数被减为了负数,这是Linux物理页管理程序所不允许 的,所以执行了mm/memory.c中free_page函数的最后一行(第310行)代码打印出错信息。请读者改进 sys_shmget函数,当能够使用key从vector中获取共享的物理页时,将此物理页在mem_map中的引用计数增 加1该如何修改。
可以在sys_shmget函数中找到使用get_free_page函数申请到一个物理页的代码,在此代码后面添加mem_map引用计数增加的代码即可。具体实现如下:
```C
unsigned long sys_shmget(key_t key, size_t size, int shmflg)
{
struct shmid_ds *buf;
struct shminfo *inf;
struct shm_file_data *shm_file;
struct page *page;
unsigned long addr;
int shmid, err, temp;
int i;
down(&shm_ids.sem);
// 查找 key 对应的共享内存是否已经存在
for (i = 0; i < SHM_NR; i++) {
if (shm_ids.used_ids[i] &&
shm_ids.shm_file[i]->key == key) {
shm_file = shm_ids.shm_file[i];
break;
}
}
// 如果 key 对应的共享内存不存在,就创建一个新的共享内存
if (i == SHM_NR) {
if (!(shmflg & IPC_CREAT)) { // 如果没有创建新的共享内存的权限
up(&shm_ids.sem);
return -EINVAL;
}
// 查找一个空闲的共享内存结构体
for (i = 0; i < SHM_NR; i++) {
if (!shm_ids.used_ids[i]) {
shm_file = kmalloc(sizeof(struct shm_file_data), GFP_KERNEL);
if (!shm_file) {
up(&shm_ids.sem);
return -ENOMEM;
}
// 申请一个物理页
page = get_free_page();
if (!page) {
up(&shm_ids.sem);
kfree(shm_file);
return -ENOMEM;
}
// 将物理页映射到内核空间
addr = (unsigned long) page_address(page);
if (!addr) {
up(&shm_ids.sem);
free_page((unsigned long) page);
kfree(shm_file);
return -ENOMEM;
}
// 初始化共享内存结构体
shm_file->key = key;
shm_file->page = page;
shm_file->attached = 0;
// 将共享内存结构体添加到 vector 中
temp = find_empty_slot();
if (temp == -1) {
up(&shm_ids.sem);
free_page((unsigned long) page);
kfree(shm_file);
return -EINVAL;
}
shm_ids.used_ids[temp] = 1;
shm_ids.shm_file[temp] = shm_file;
// 设置物理页在 mem_map 中的引用计数
atomic_inc(&mem_map[MAP_NR(page->phys_addr)].count);
buf = (struct shmid_ds *) getname(kernel_stack, (char *) arg2);
if (!buf) {
up(&shm_ids.sem);
free_page((unsigned long) page);
kfree(shm_file);
return -EFAULT;
}
// 初始化共享内存的元信息
buf->shm_nattch = 0;
buf->shm_page = page;
buf->shm_segsz = PAGE_SIZE;
putname((char *) arg2);
up(&shm_ids.sem);
return temp;
}
}
up(&shm_ids.sem);
return -EINVAL;
}
// 如果 key 对应的共享内存已经存在,就返回共享内存的编号
shmid = i;
shm_file = shm_ids.shm_file[shmid];
// 设置物理页在 mem_map 中的引用计数
atomic_inc(&mem_map[MAP_NR(shm_file->page->phys_addr)].count);
up(&shm_ids.sem);
return shmid;
}
```
在上述代码中,我们在申请到物理页后,添加了以下代码:
```C
// 设置物理页在 mem_map 中的引用计数
atomic_inc(&mem_map[MAP_NR(page->phys_addr)].count);
```
这样,在使用key从vector中获取共享的物理页时,就会增加此物理页在mem_map中的引用计数,从而避免了引用计数被减为负数的问题。
使用系统调用SHMGET(),SHMAT()编制一长度为1K的消息发送和接收的程序。 要求: (1)main函数建立一个KEY 为75 的共享区,并将第一个字节置为0。作为数据空的标志等待其他进程发来的消息。收到数据后显示“ Main recieved help ”。 (3)创建一个进程P1,P1建立一个KEY为75的共享区,当共享取得第一个字节为0时,main空闲,可发送请求:P1填入“HELP”,发送数据后显示“P1 send help”。
好的,这是一个稍微复杂一些的问题,需要编写两个程序,一个用来发送消息,另一个用来接收消息。下面分别介绍这两个程序的实现。
程序一:发送消息
首先,需要引入以下头文件:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <string.h>
```
然后,我们可以定义一个结构体,用来存储共享内存区中的数据:
```c
struct shared_data {
char data[1024];
};
```
接下来,我们可以编写主函数:
```c
int main() {
int shmid;
struct shared_data *shared_mem;
key_t key = 75;
// 创建共享内存区
shmid = shmget(key, sizeof(struct shared_data), IPC_CREAT | 0666);
if (shmid < 0) {
perror("shmget");
exit(1);
}
// 附加共享内存区
shared_mem = (struct shared_data *) shmat(shmid, NULL, 0);
if (shared_mem == (struct shared_data *) -1) {
perror("shmat");
exit(1);
}
// 循环等待共享内存区第一个字节为0
while (shared_mem->data[0] != 0);
// 将消息填入共享内存区,并将第一个字节置为1
strcpy(shared_mem->data, "HELP");
shared_mem->data[0] = 1;
printf("P1 send help\n");
// 分离共享内存区
shmdt(shared_mem);
return 0;
}
```
在上面的代码中,我们首先创建了一个 KEY 为 75 的共享内存区,并循环等待共享内存区第一个字节为0。如果第一个字节为0,就将消息填入共享内存区,并将第一个字节置为1,表示共享内存区中有数据可供接收。最后,分离共享内存区。
程序二:接收消息
首先,需要引入以下头文件:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <string.h>
```
然后,我们可以定义一个结构体,用来存储共享内存区中的数据:
```c
struct shared_data {
char data[1024];
};
```
接下来,我们可以编写主函数:
```c
int main() {
int shmid;
struct shared_data *shared_mem;
key_t key = 75;
// 创建共享内存区
shmid = shmget(key, sizeof(struct shared_data), IPC_CREAT | 0666);
if (shmid < 0) {
perror("shmget");
exit(1);
}
// 附加共享内存区
shared_mem = (struct shared_data *) shmat(shmid, NULL, 0);
if (shared_mem == (struct shared_data *) -1) {
perror("shmat");
exit(1);
}
// 将第一个字节置为0,作为数据空的标志
shared_mem->data[0] = 0;
// 循环等待其他进程发来的消息
while (1) {
if (shared_mem->data[0] == 1) {
printf("Main recieved %s\n", shared_mem->data);
shared_mem->data[0] = 0;
break;
}
}
// 分离共享内存区
shmdt(shared_mem);
// 删除共享内存区
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
```
在上面的代码中,我们首先创建了一个 KEY 为 75 的共享内存区,并将第一个字节置为0,作为数据空的标志。然后,我们进入一个循环,等待其他进程发来的消息。如果收到了消息,就将第一个字节置为0,并显示 "Main recieved"。
注意,在接收消息的程序中,我们还需要删除共享内存区,因为这个程序是最后一个使用这个共享内存区的程序。
这样,我们就完成了一个基于共享内存的消息发送和接收的程序。
阅读全文