共享内存段中的链接列表

时间:2017-12-12 05:42:55

标签: c struct linked-list shared-memory

我目前正处理一个链接列表,一个链表节点有多个可变数据的部分,要保存在共享内存段中,以便另一个程序可以读取该列表并相应地执行操作。

我之前曾参与套接字编程,但发送数据流并不符合我的目的,因为我必须根据一次读取一个节点/元素进行验证。因此,在所有IPC中,我认为共享内存将是最好的,因为它也具有良好的性能(在这种情况下,通常不是)。

以下是我所做的结构:

    struct DNode {
    char *polname;
    char *devname;
    char *status;
    char *srczone;
    char *dstzone;
    char *srcaddr;
    char *dstaddr;
    char *srcuser;
    char *app;
    char *service;
    char *urlcategory;
    char *action;
    char *vulnerability;

    char *value;
    struct DNode *next;
        };
    struct DNode *head = NULL;

struct DList {
    DNode pool[MAX_DNODE];      // fixed-size space for nodes
    size_t npool;               // used space in pool
    size_t pfree;               // pointer to re-use freed nodes
    size_t head;                // global list head
};

DList *dlist;
    DNode *dnode_alloc(void)
{
    if (dlist->pfree != DNULL) {
        DNode *node = dlist->pool + dlist->pfree;

        dlist->pfree = dlist->pool[dlist->pfree].next;
        return node;
    } else {
        if (dlist->npool < MAX_DNODE) return &dlist->pool[dlist->npool++];
    }

    return NULL;
}
void dnode_free(DNode *node)
{
    if (node) {
        node->next = dlist->pfree;
        dlist->pfree = node - dlist->pool;
    }
}

DNode *dnode(size_t index)
{
    return (index == DNULL) ? NULL : dlist->pool + index;
}

DNode *dnode_next(const DNode *node)
{
    return dnode(node->next);
}

DNode *dnode_push(size_t *head, const char *str)
{
    DNode *node = dnode_alloc();

    if (node) {
        strncpy(node->polname, str, sizeof(node->polname));
        node->next = *head;
        *head = node - dlist->pool;
    }

    return node;
}

    void dnode_pop(size_t *head)
{
    if (*head != DNULL) {
        size_t next = dlist->pool[*head].next;

        dnode_free(&dlist->pool[*head]);
        *head = next;
    }
}
int list_insert_front(struct node* new_node) {
        struct node *temp;
        temp = malloc(sizeof *temp);
        if (temp && new_node) {
            memcpy(temp, new_node, sizeof(struct node));
            temp->next = head;
            head = temp;
            return 1;
        }
        return 0;
    }

       int main(int argc, char **argv)
{
   struct Dnode *iter = head;
    int shmid;
    xmlDocPtr doc;
    xmlNode *root_element = NULL;


    if (argc != 2)
    {
        printf("\nInvalid argument\n");
        return(1);
    }

    doc = xmlReadFile(argv[1], NULL, XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING | XML_PARSE_NONET);
    if (doc == NULL)
    {
        fprintf(stderr, "Document not parsed successfully.\n");
        return 0;
    }

    root_element = xmlDocGetRootElement(doc);

    if (root_element == NULL)
 {
        fprintf(stderr, "empty document\n");
        xmlFreeDoc(doc);
        return 0;
    }

    printf("Root Node is %s\n", root_element->name);
    traverse_dom_trees(root_element);

    shmid = shmget(IPC_PRIVATE, sizeof(DList), IPC_CREAT | 0660);
    if (shmid < 0) exit (1);

    dlist = shmat(shmid, NULL, 0);
    if (dlist == (void *) (-1)) exit(1);

    dlist->head = DNULL;
    dlist->pfree = DNULL;
    dlist->npool = 0;

    while(iter != NULL){
dnode_push(&dlist->head, head->polname);
    dnode_pop(&dlist->head);
    iter = head->next;
    }


    shmdt(dlist);
    xmlFreeDoc(doc);       // free document
    xmlCleanupParser();    // Free globals
    return 0;
}

正如您所看到的,我还在main函数中包含了一个XML解析器部分,以便您了解我正在将其作为输入。但我遇到的部分是如何在共享内存中保存/使用此结构,并使其他程序可以轻松访问它。

请有人能为我提供一些伪代码,因为我之前从未使用过这样的C功能,而且对于如何处理这个问题绝对毫无头绪。 欢迎任何和所有建议,并提前感谢。

修改1

在虚拟机上使用Centos7,因为有人指出提及平台会很有成效。

编辑2 刚刚添加了一些代码来实现共享内存段,它并没有给我任何这样的错误。我关心的是:

  • 它正在按我的意图行事吗?
  • 方法是否正确?
  • 我知道我目前只是在推动一个元素,但这肯定是对的,对吗?
  • 我是否在浪费时间和努力尝试使用共享内存进行解决?

2 个答案:

答案 0 :(得分:0)

您需要:

  • 在您的平台上设置共享内存 - 请参阅here
  • 在您的计划中,请致电public Map<String, List<PatientInfo>> getPatients(String sendingApplication,String sendingFacility) { // TODO Auto-generated method stub Map<String, List<PatientInfo>> patientMap = null; List<PatientInfo> patientList = null; patientMap = new HashMap<String, List<PatientInfo>>(); patientList = new ArrayList<PatientInfo>(); try { PatientInfoDAO patientInfoDAO = new PatientInfoDAOImpl(); ItemCollection<QueryOutcome> items = patientInfoDAO.getPatients(sendingApplication, sendingFacility); for(Item item : items){ PatientInfo patient = new PatientInfo(); patient.setAdministrativeSex(item.getString("")); patient.setFamilyName(item.getString("FAMILYNAME")); patient.setGivenName(item.getString("GIVENNAME")); patient.setAdmitDateOrTime(item.getString("GENDER")); patient.setAssignedPatientLocationBuilding(item.getString("USERNAME")); patient.setAssignedPatientLocationFloor(item.getString("PASSWORD")); patient.setAssignedPatientLocationPersonLocationType(item.getString("USERROLE")); patient.setAssignedPatientLocationRoom(item.getString("USERSTATUS")); patient.setAsssignedPatientLocationBed(item.getString("EMAIL")); patient.setAttendingDoctor(item.getString("EMROPERATOR")); patient.setClientId(item.getString("clientId")); patient.setDateOrTimeOfMessage(item.getString("dateOrTimeOfMessage")); patient.setDischargeDateOrTime(item.getString("dischargeDateOrTime")); patient.setDob(item.getString("dob")); patient.setEventOccuredTime(item.getString("eventOccuredTime")); patient.setImageUrl(item.getString("imageUrl")); patient.setLastModifiedOn(item.getString("lastModifiedOn")); patient.setMessageControlId(item.getString("messageControlId")); patient.setNrPatientId(item.getString("nrPatientId")); patient.setPatientId(item.getString("patientId")); patient.setPatientStatus(item.getString("patientStatus")); patient.setPriorPatientLocationBed(item.getString("priorPatientLocationBed")); patient.setPriorPatientLocationBuilding(item.getString("priorPatientLocationBuilding")); patient.setPriorPatientLocationFloor(item.getString("priorPatientLocationFloor")); patient.setPriorPatientLocationPersonLocationType(item.getString("priorPatientLocationPersonLocationType")); patient.setPriorPatientLocationPointOfCare(item.getString("priorPatientLocationPointOfCare")); patient.setPriorPatientLocationRoom(item.getString("priorPatientLocationRoom")); patient.setReceivingFacility(item.getString("receivingFacility")); patient.setRecevingApplication(item.getString("recevingApplication")); patient.setSendingApplicaation(item.getString("sendingApplicaation")); patient.setSendingFacility(item.getString("sendingFacility")); patientList.add(patient); } String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); patientMap.put("PATIENTLIST", patientList); patientMap.put("LASTKEY", date); return patientMap; }catch(AmazonServiceException ase){ throw new RuntimeException("internalServerError"); }catch(AmazonClientException ase){ throw new RuntimeException("internalServerError"); } } 打开共享内存并使用shm_open使用指针访问它 - 请参阅here
  • 从不同进程/线程访问共享内存必须使用一些仲裁/互斥机制 - 请参阅here

答案 1 :(得分:0)

通常,您无法保证共享内存段在一个进程中占用的虚拟地址范围与其他进程相同。因此,在尝试解释指针字段中的值时会遇到问题,因为它们表示在那里写入指针值的进程的虚拟地址空间中指向对象的地址如果两个进程在不同的位置映射共享内存段,则可以不同。

您可以通过mmap调用指针来告诉系统您希望在哪个虚拟地址空间中映射段,因此共享指针指向两个虚拟地址空间中的相同位置。但该指针只是一个提示,操作系统不会被强制跟随你的指针。

有两种解决方案。第一个是偏移指针值,因此您构建您在共享段中看到的虚拟地址空间指针。第二是确保您的内存段都映射到同一地址。这必须在两个进程之间进行协调(但是在内存映射时只需要进行一次),因为对于另一个进程可以禁止对另一个有利的地方(因为它已经映射了其他一些东西)

在64位体系结构中,这很容易,因为您有足够的虚拟地址来映射段,并且可能您可以选择一个地址而不会与其他子系统发生冲突。认为在32位系统中,通常共享库为这里的模块的数据段消耗了一堆地址,并且堆栈提供了大量内存,而堆也是......所以你必须在之前计划事情。尝试将两个段放在共享的相同地址中。

在您的特定情况下,几乎所有结构的字段都是指针,这适用于所有字段,而不仅仅是链接的字段。不仅所有列表节点都必须位于共享段中......还有所有字符串,以及您访问的所有内容都是共享的。