Thread: shareing a hashtable containing a linkedlist between processes

  1. #1
    Registered User
    Join Date
    Feb 2023
    Posts
    2

    shareing a hashtable containing a linkedlist between processes

    As the title hints at, I have a key/value hash table where the keys are strings and the values are Linked lists. I would like to change the data in the linked lists from child processes. How can i do this? Is there a way to make the pointer to the hash table available between processes?

    Or how to access a function in the parent process would work to.
    Last edited by madsenofthebft; 02-19-2023 at 06:53 PM.

  2. #2
    Registered User
    Join Date
    Feb 2023
    Posts
    12
    How can i do this? Is there a way to make the pointer to the hash table available between processes?
    Yes, there is absolutely a way to do this. What you're looking for is a concept known as shared memory. Every modern operating system supports it (Windows, Linux, BSD, and MacOS, although you apparently need some setup for it..)

    As for how you can do it.. well, it depends on your operating system. We will need a bit more information to help you out here.

  3. #3
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    You also need to be careful how you coordinate multiple process accessing the shared memory, and in same cases caches between processes.

    If you only add entries into the structures you can sometimes get by with a lockless system.

    If also need to remove data from the structure you definitely need some form of locking.

  4. #4
    Registered User
    Join Date
    Feb 2023
    Posts
    2
    Quote Originally Posted by madsenofthebft View Post
    As the title hints at, I have a key/value hash table where the keys are strings and the values are Linked lists. I would like to change the data in the linked lists from child processes. How can i do this? Is there a way to make the pointer to the hash table available between processes?

    Or how to access a function in the parent process would work to.
    I will elaborate.

    Im creating kind of a chat application, the connected users are in "rooms" and can change to another room. The rooms are the hash table keys and the values are lists of all the connected users. A message from a user goes out to all the other users in the same room. As a user connects the program forks and the childprocess needs to be able to use the hashtable to send messages to the other users, or change room.

    Im currently compiling it for ubuntu.

    I accomplished this with threads but now i want to use fork instead. It seemed like a better idea.

  5. #5
    Registered User
    Join Date
    Feb 2023
    Posts
    12
    Good morning.

    Im currently compiling it for ubuntu.
    Sounds good. So, you got two primary options here. POSIX shared memory, and the shared memory API from System V. I will give an example of how to use System V API, but I can also cook up an example of the POSIX API if you'd like.

    So, first off, we have the host process which creates, and writes to the shared memory. If you copy these examples into your computer, make sure they are both in the same directory.

    The host process will create a new file called SHARED, which is used by the host and client processes to gain access to the shared memory (UNIX and its derivatives are (in)famous for their use of the file system as a namespace of sorts).

    The host process will generate a key based off the path to the file, and this key is used to both create and access a shared memory segment. The key generation is deterministic-- based off of the file path-- which allows for both processes to access the same shared memory.

    The key is used to tell shmget. to return the id of the shared memory segment, creating it if it doesn't exist, or just returning the existing one if it does exist. We then grant our process access to the shared memory using shmat.

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    /* This is the structure we want to reserve space in shared
     * memory for */
    struct User {
        char name[32];
        char password[32];
    };
    
    /* Create a new shared memory segment with the id '0' from
     * a new file, returning the id of the shared memory segment */
    int create_shared_memory(const char *path, size_t size) {
        FILE *new_file = fopen(path, "w");
    
        fclose(new_file);
    
        return shmget(ftok(path, 0), size, IPC_CREAT);
    }
    
    /* Detach the memory location, preventing us from accessing
     * it, and delete the shared memory segment. */
    void delete_shared_memory(void *location, int id) {
        shmdt(location);
        shmctl(id, IPC_RMID, NULL);
    }
    
    int main(void) {
        /* We want this shared memory segment to have a size
         * big enough to hold this structure. */
        int id = create_shared_memory("./SHARED", sizeof(struct User));
        struct User *user = shmat(id, NULL, 0);
    
        /* Write the username and password to the memory segment */
        strncat(user->name, "bob", 32 - 1);
        strncat(user->password, "12345", 32 - 1);
    
        /* Give the client process time to read the password */
        fgetc(stdin);
    
        delete_shared_memory(user, id);
    
        return 0;
    }
    And the client code..

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    /* This is the structure we want to reserve space in shared
     * memory for */
    struct User {
        char name[32];
        char password[32];
    };
    
    /* Normally, this would create a new shared memory segment,
     * but this should be called *AFTER* the host process was
     * spawned so it can create the shared memory. However, we
     * still need to get the shared memory id, and will instead
     * simply get the existing one. */
    int get_shared_memory(const char *path, size_t size) {
        return shmget(ftok(path, 0), size, IPC_CREAT);
    }
    
    /* Detach the memory location, preventing us from accessing
     * it. The host process should handle deletion of the shared
     * memory. */
    void delete_shared_memory(void *location, int id) {
        shmdt(location);
    }
    
    int main(void) {
        /* We want this shared memory segment to have a size
         * big enough to hold this structure. */
        int id = get_shared_memory("./SHARED", sizeof(struct User));
        struct User *user = shmat(id, NULL, 0);
    
        /* Read the username and password to the memory segment */
        printf("My username: %s\n", user->name);
        printf("My password: %s\n", user->password);
    
        /* Detatch the shared memory segment */
        delete_shared_memory(user, id);
    
        return 0;
    }
    This is, of course, a fair bit of information to throw at you. If you are confused about anything, please, tell me and I will try to elaborate or simplify where needed.

    the connected users are in "rooms" and can change to another room. The rooms are the hash table keys and the values are lists of all the connected users. A message from a user goes out to all the other users in the same room. As a user connects the program forks and the childprocess needs to be able to use the hashtable to send messages to the other users, or change room.
    I'm going to be honest.. the choice to use shared memory as a strategy here seems like a bad idea! Forking a process carries a lot of subtle implications. Unless you used shared memory as a temporary spot to store messages (e.g writing one message at a time to the shared memory, having the other processes copy it, and repeating when there is a new message), then you will probably have a lot of other problems.

    Even if you were doing the simplified example I provided, you would still need to synchronize the processes which is a whole other topic. If you ask me, the better solution to this problem is sockets! Using sockets, you can keep things single threaded by multiplexing using poll or select, arguably decreasing complexity, so I think that might be the better route for you.

  6. #6
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Oh, a rookie mistake is forking with data file handles open.... when you move the file pointer in one one process it will move the file pointer in all processes that are using the same file handle.

  7. #7
    Registered User
    Join Date
    Feb 2023
    Posts
    12
    Quote Originally Posted by hamster_nz View Post
    Oh, a rookie mistake is forking with data file handles open.... when you move the file pointer in one one process it will move the file pointer in all processes that are using the same file handle.
    Yup. It's not only file handles, but all memory that the parent process had is copied into the child process. Granted, modern operating systems use copy-on-write semantics, meaning that the memory is not actually copied into the child processes memory space until the child or parent process attempts to write to it, and until a write attempt is made, the child process is granted access to the parent processes' address space.

    Usually, however, this is not a problem, as forking processes is usually immediately followed by one of the exec family of functions and thus the memory is discarded. But sometimes, you use fork for other purposes and thus must pay special attention.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Hashtable
    By RyanC in forum C Programming
    Replies: 4
    Last Post: 05-23-2019, 06:45 PM
  2. Initializing a hashtable?
    By mrsirpoopsalot in forum C++ Programming
    Replies: 3
    Last Post: 11-19-2009, 01:19 AM
  3. HashTable help?
    By -EquinoX- in forum C Programming
    Replies: 66
    Last Post: 03-31-2008, 12:15 AM
  4. Replies: 12
    Last Post: 10-22-2006, 08:37 PM
  5. game hashtable
    By disks86 in forum C++ Programming
    Replies: 1
    Last Post: 12-16-2005, 01:42 PM

Tags for this Thread