我正在尝试在共享内存中共享一个链表,但是在使用fork()
时遇到一些问题,没有fork()
的话,它可以正常工作,但是我必须至少有一个子进程。
如果没有子代,它将起作用,但是当我创建一个子代进程并使用addValue
函数时,结果是分段错误。
由于进行了大量更改,因此代码不是很好。我尝试使用malloc
,但无法完成处理。
[在某些论坛中搜索,关于共享链表有不同的想法,但没有一个起作用。
另一个关于我有shmget()
的疑问,我必须通过sizeof(struct Request)
,但有时如果链接列表可以处理的最大节点池数量,则有时它们会通过sizeof(struct Request)*n
,但有时它们使用具有不同键的shmget
就像我写的这段代码。因此,另一个问题是:sizeof()*n
或具有多个size()
键的shmget
?
#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <unistd.h>
#include <sys/ipc.h>
struct Request{
int value;
struct Request *next;
}Request;
void errorHandler(char *msg){
perror(msg);
exit(EXIT_FAILURE);
}
struct Request *getNode(key_t key){
int shmid = shmget(key, sizeof(struct Request), IPC_CREAT | 0660);
if(shmid==-1){
errorHandler("SHMGET7");
}
struct Request *req = shmat(shmid, NULL, 0);
if(req==(void *)-1){
errorHandler("SHMAT9");
}
return req;
}
void addValue(key_t headKey, key_t newKey, int value){
struct Request *head = getNode(headKey);
while(head->next!=NULL){
head = head->next;
}
struct Request *node = getNode(newKey);
node->value = value;
node->next = NULL;
head->next = node;
}
void printNodes(key_t key){
struct Request *head = getNode(key);
while(head!=NULL){
printf("%d\n", head->value);
head = head->next;
}
}
int main(int argc, char *argv[]){
key_t key = 1234;
struct Request *req = getNode(key);
req->value = -1;
req->next = NULL;
key_t newKey = 250;
addValue(key, newKey, 100);
newKey = 251;
addValue(key, newKey, 101);
for(int i=0;i<2;i++){
pid_t pid = fork();
if(pid==-1){
errorHandler("FORK");
}else if(pid==0){
newKey = 252+i;
addValue(key, newKey, 101);
exit(0);
}
sleep(1);
}
for(int i=0;i<2;i++){
wait(NULL);
}
printNodes(key);
printf("end\n");
return 0;
}
对于shmdt
,我必须循环链接列表,并shmdt
每个节点?
如果没有子代,它将起作用,但是当我创建一个子代进程并使用addValue函数时,结果是分段错误。
shmat(<id>, NULL, <flg>)
返回的地址仅对当前进程有效,要在其他进程中使用它具有未定义的行为。
对于第一个fork,该列表包含来自父级的有效地址,因为子级继承了附加的共享内存段。但是在第二个回合(i值为1),第二个fork尝试使用一个无效的地址,也不使用printNodes
中稍后的主进程,因为它来自第一个fork] >并且仅对此有效。出于相同的原因,假设主进程能够通过shmap
获得第二个fork的地址返回,该地址也不能被取消引用。
我必须传递sizeof(struct Request),但有时...
这是正确的大小,因为您要分配一个单元格,使用
malloc
所需的大小是相同的。
解决问题的一种方法是将密钥用于next
,而不是在当前进程及其子进程中无效的地址。
对代码进行最小的更改,使用键0作为NULL指针,修改后的定义是:
struct Request{ int value; key_t next; } Request;
和
:void addValue(key_t headKey, key_t newKey, int value){ struct Request *head = getNode(headKey); while(head->next!=0){ headKey = head->next; head = getNode(headKey); } struct Request *node = getNode(newKey); node->value = value; node->next = 0; head->next = newKey; } void printNodes(key_t key) { while (key != 0) { struct Request *head = getNode(key); printf("%d\n", head->value); key = head->next; } }
以及开头或main
req->next = 0;
之后,编译和执行(我添加了
#include <sys/wait.h>
):
pi@raspberrypi:/tmp $ gcc -g -Wall l.c
pi@raspberrypi:/tmp $ ./a.out
i=0
i=1
-1
100
101
101
101
end
pi@raspberrypi:/tmp $