我正在编写一个服务器程序,它从客户端接收消息并向所有以前的客户端发送广播消息。我需要在进程之间创建共享内存,但似乎共享内存不起作用。
这是我的代码:
int shmid2; key_t key2; void* shm2;
string name_list;
key2=ftok("tmp",'d');
//create
if ((shmid2 = shmget ( key2, sizeof(char)*1000, IPC_CREAT | 0666)) < 0) {
perror("shmget2");
exit(1);}
//attach
shm2 = shmat(shmid2, (void *)0, 0) ;
name_list= (char*) shm2;
if ( shm2 == (char *) -1) {
perror("shmat2");
exit(1);}
... do other things...
switch (pid=fork()){
case -1:
{ perror("ERROR on fork");
break;}
case 0://children
{
...modify name_list by getting message and append message to name_list..
name_list.append(message);
break;}
default://parent
close(connection);
}
当我在子进程中修改name_list时,似乎其他进程看不到此修改。 谁能提出任何建议?谢谢!
更新:我尝试按建议更改为此,但仍然无效。
name_list = (char*) shmat(shmid2, (void *)0, 0) ;
任何人都可以帮我这个吗?非常感谢!
答案 0 :(得分:1)
将std::string
对象name_list
分配给从共享内存中获取的指针时:
string name_list;
// ...
shm2 = shmat(shmid2, (void *)0, 0) ;
name_list= (char*) shm2;
// ...
name_list.append(message);
你正在调用字符串的赋值运算符,将指定的指针复制到新内存中。当您的代码操作name_list
时,它正在操纵副本,保持共享内存不受影响。
看起来你正试图从一个进程写入共享内存,并在另一个进程中读取它,这不是一个需要解决的小问题。弄清楚哪个进程可以读取和写入哪些内存是棘手的,就像维护缓存一致性一样。查找生产者 - 消费者循环缓冲区(在Google上或此处在Stack Overflow上),以获得此问题的一些标准解决方案。
要回答原始问题,一旦在本地内存中操作了字符串,就需要将其放回共享内存中。这将在紧要关头:
if(name_list.size() <= 1000) {
memcpy(shm2, name_list.data(), name_list.size());
} else {
// error: name list overflowed shared memory
}
你也可以使用指针shm2
直接操作共享内存,直接使用C指针,注意不要溢出1000字节的缓冲区。
答案 1 :(得分:0)
总结一下: 如果使用字符串类,则始终会操作共享内存的副本。
两种解决方案: 1.不要使用字符串而是使用标准C方法直接操作char数组(strcat例如附加字符) 2.完成name_list的修改后,将其复制回共享内存。
版本1更快。版本2更简单。