Linux 与 C++ 的共享内存:分段错误
Linux Shared Memory with C++: Segmentation Fault
我正在关注 Linux 编程接口书(第 1004-1005 页)。
我知道这本书使用 C。但我想在 C++ 中实现相同的行为。即:通过共享内存在进程间共享一个struct。
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
struct my_pair {
int a;
int b;
};
int main()
{
key_t key = ftok("aaaaa", 1);
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
my_pair *numbers;
numbers = shmat(shmid, NULL, 0);
cout << numbers->a;
return 0;
}
它给我这个错误:
shteste.cpp: In function 'int main()':
shteste.cpp:18: error: invalid conversion from 'void*' to 'my_pair*'
我知道C++更严格。如果我将 shmat 的 return 转换为 (my_pair *),它会编译但在执行期间会出现分段错误。
是否可以(如何)将 Linux / C 共享内存设施与 C++ 一起使用?
我正在编译:G++ 4.4.7:g++ shteste.cpp -o shteste -std=c++0x
谢谢...
编辑:根据所有建议,现在是代码:
int main()
{
key_t key;
if ((key = ftok("/home/alunos/scd/g11/aaaaa", 1)) == (key_t) -1) {
perror("IPC error: ftok"); exit(1);
}
int shmid = shmget(key , sizeof(my_pair), IPC_CREAT | 0640);
if (shmid == -1) {
perror("Could not get shared memory");
return EXIT_FAILURE;
}
my_pair *numbers;
void* mem = (my_pair*) shmat(shmid, NULL, 0);
if (mem == reinterpret_cast<void*>(-1)) {
perror("Could not get shared memory location");
return EXIT_FAILURE;
} else {
numbers = reinterpret_cast<my_pair*>(mem);
cout << numbers->a;
}
return EXIT_SUCCESS;
}
aaaaa 内容:notacat
[scd11@VM11 ~]$ ./shteste
Could not get shared memory: Permission denied
这可能是权限问题。您可以检查 shmget
和 shmat
的 return 值,并使用 perror
打印这样一条人类可读的错误消息。
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct my_pair {
int a;
int b;
};
int main()
{
key_t key = ftok("aaaaa", 1);
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
if (shmid == -1) {
perror("Could not get shared memory");
return EXIT_FAILURE;
}
my_pair *numbers;
void* mem = (my_pair*) shmat(shmid, NULL, 0);
if (mem == reinterpret_cast<void*>(-1)) {
perror("Could not get shared memory location");
return EXIT_FAILURE;
} else {
numbers = reinterpret_cast<my_pair*>(mem);
cout << numbers->a;
}
return EXIT_SUCCESS;
}
根据 ftok
手册页:
The ftok() function uses the identity of the file named by the given
pathname (which must refer to an existing, accessible file).
使用现有文件,您的代码将起作用。
或者您可以使用:
key = IPC_PRIVATE
对于这个例子来说已经足够了,但不适用于真正的 IPC。
你只是忘了设置权限:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
正如我在评论中已经提到的,失败命令的结果可以通过 strace 查看。
64 5327 shmget(0xffffffff, 8, IPC_CREAT|000) = 11534358
65 5327 shmat(11534358, NULL, 0) = -1 EACCES (Permission denied)"
如果您的文件 "aaaaa" 存在,代码对我有用。
这是权限问题。
根据 the shmget()
documentation:
SYNOPSIS
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
...
DESCRIPTION
...
- The low-order nine bits of shm_perm.mode are set to the low-order nine bits of shmflg.
您没有设置任何权限位。你调用的shmflag的低九位全为零:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
您需要设置适当的权限,如下所示:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT|0640);
您可能还必须使用 ipcrm
来删除当前的共享内存段,因为它会在不正确的权限下保持原样。即使您更改代码,您的 shmget()
调用也将 return 现有细分的 ID - 由于缺少权限而您无法附加的 ID。
首先,使用ipcs -a
列出共享内存段,然后使用ipcrm -m shmid
或ipcrm -M shmkey
删除权限不正确的段。
我正在关注 Linux 编程接口书(第 1004-1005 页)。
我知道这本书使用 C。但我想在 C++ 中实现相同的行为。即:通过共享内存在进程间共享一个struct。
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
struct my_pair {
int a;
int b;
};
int main()
{
key_t key = ftok("aaaaa", 1);
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
my_pair *numbers;
numbers = shmat(shmid, NULL, 0);
cout << numbers->a;
return 0;
}
它给我这个错误:
shteste.cpp: In function 'int main()':
shteste.cpp:18: error: invalid conversion from 'void*' to 'my_pair*'
我知道C++更严格。如果我将 shmat 的 return 转换为 (my_pair *),它会编译但在执行期间会出现分段错误。
是否可以(如何)将 Linux / C 共享内存设施与 C++ 一起使用?
我正在编译:G++ 4.4.7:g++ shteste.cpp -o shteste -std=c++0x
谢谢...
编辑:根据所有建议,现在是代码:
int main()
{
key_t key;
if ((key = ftok("/home/alunos/scd/g11/aaaaa", 1)) == (key_t) -1) {
perror("IPC error: ftok"); exit(1);
}
int shmid = shmget(key , sizeof(my_pair), IPC_CREAT | 0640);
if (shmid == -1) {
perror("Could not get shared memory");
return EXIT_FAILURE;
}
my_pair *numbers;
void* mem = (my_pair*) shmat(shmid, NULL, 0);
if (mem == reinterpret_cast<void*>(-1)) {
perror("Could not get shared memory location");
return EXIT_FAILURE;
} else {
numbers = reinterpret_cast<my_pair*>(mem);
cout << numbers->a;
}
return EXIT_SUCCESS;
}
aaaaa 内容:notacat
[scd11@VM11 ~]$ ./shteste
Could not get shared memory: Permission denied
这可能是权限问题。您可以检查 shmget
和 shmat
的 return 值,并使用 perror
打印这样一条人类可读的错误消息。
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
struct my_pair {
int a;
int b;
};
int main()
{
key_t key = ftok("aaaaa", 1);
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
if (shmid == -1) {
perror("Could not get shared memory");
return EXIT_FAILURE;
}
my_pair *numbers;
void* mem = (my_pair*) shmat(shmid, NULL, 0);
if (mem == reinterpret_cast<void*>(-1)) {
perror("Could not get shared memory location");
return EXIT_FAILURE;
} else {
numbers = reinterpret_cast<my_pair*>(mem);
cout << numbers->a;
}
return EXIT_SUCCESS;
}
根据 ftok
手册页:
The ftok() function uses the identity of the file named by the given
pathname (which must refer to an existing, accessible file).
使用现有文件,您的代码将起作用。
或者您可以使用:
key = IPC_PRIVATE
对于这个例子来说已经足够了,但不适用于真正的 IPC。
你只是忘了设置权限:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT | 0777);
正如我在评论中已经提到的,失败命令的结果可以通过 strace 查看。
64 5327 shmget(0xffffffff, 8, IPC_CREAT|000) = 11534358
65 5327 shmat(11534358, NULL, 0) = -1 EACCES (Permission denied)"
如果您的文件 "aaaaa" 存在,代码对我有用。
这是权限问题。
根据 the shmget()
documentation:
SYNOPSIS
#include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg);
...
DESCRIPTION
...
- The low-order nine bits of shm_perm.mode are set to the low-order nine bits of shmflg.
您没有设置任何权限位。你调用的shmflag的低九位全为零:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT);
您需要设置适当的权限,如下所示:
int shmid = shmget(key, sizeof(my_pair), IPC_CREAT|0640);
您可能还必须使用 ipcrm
来删除当前的共享内存段,因为它会在不正确的权限下保持原样。即使您更改代码,您的 shmget()
调用也将 return 现有细分的 ID - 由于缺少权限而您无法附加的 ID。
首先,使用ipcs -a
列出共享内存段,然后使用ipcrm -m shmid
或ipcrm -M shmkey
删除权限不正确的段。