有可能在C++中分配一个列表到共享内存吗?

有可能在C++中分配一个列表到共享内存吗?,c++,fork,mmap,C++,Fork,Mmap,我正在创建一个服务器,其中有一个处理客户机的类,一个处理服务器的类,还有一个将每个新客户机显示在列表框中的类。我希望这样做并使其大部分工作正常的方式是,使用fork在子进程上运行服务器,在父进程上运行listbox。我希望能够有一个包含不同客户机类的共享列表。在python中,这将通过多处理管理器完成。我一直找不到那样的东西。我目前尝试的方法是使用mmap。到目前为止,我基本上就是这样编写代码的: 我的相关头文件: #include <list> #include <sys/m

我正在创建一个服务器,其中有一个处理客户机的类,一个处理服务器的类,还有一个将每个新客户机显示在列表框中的类。我希望这样做并使其大部分工作正常的方式是,使用fork在子进程上运行服务器,在父进程上运行listbox。我希望能够有一个包含不同客户机类的共享列表。在python中,这将通过多处理管理器完成。我一直找不到那样的东西。我目前尝试的方法是使用mmap。到目前为止,我基本上就是这样编写代码的:

我的相关头文件:

#include <list>
#include <sys/mman.h>

这就是我的服务器类初始化的样子:

class Server{
    bool running=false;
    char *ip;
    int Port;
    std::list<ClientHolder> *Clients;
    size_t pagesize = getpagesize();
    int *quit_call = static_cast<int*>(mmap(NULL, (pagesize*(1 << 20)),
                PROT_READ | PROT_WRITE,
                MAP_SHARED | MAP_ANONYMOUS, 0, 0));
    public:
        Server(std::list<ClientHolder> Clients){Clients = Clients;};
此外,quit_call变量可以按照我的要求工作。显然,我的类和代码还有很多。我只是想确切地说明什么是相关的

还应该注意的是,使用clang++编译时不会出现任何警告或错误。除了每次运行它时,我都会遇到一个zsh:分段错误,这意味着它试图读取或写入非法内存。有没有办法做我想做的事

std::list<ClientHolder> *Clients = static_cast<std::list<ClientHolder>*>(mmap(NULL, (pagesize*(1 << 20)),
            PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, 0, 0));
这行不通。list类分配内存并存储指针。这些指针在另一个进程中无效。您不能以这种方式共享std::list实例,因为每个进程都会将指向其自身内存空间的指针写入共享内存中的std::list实例,而另一个进程在尝试取消引用它们时会崩溃

您将需要分配更多的共享内存,足以容纳您想要共享的所有内容。您需要为std::list提供一个分配器,该分配器只分配共享内存的块,以便另一个进程能够理解放入共享内存的指针

这可能比它的价值更麻烦,您可能会更好地重新考虑设计

这行不通。list类分配内存并存储指针。这些指针在另一个进程中无效。您不能以这种方式共享std::list实例,因为每个进程都会将指向其自身内存空间的指针写入共享内存中的std::list实例,而另一个进程在尝试取消引用它们时会崩溃

您将需要分配更多的共享内存,足以容纳您想要共享的所有内容。您需要为std::list提供一个分配器,该分配器只分配共享内存的块,以便另一个进程能够理解放入共享内存的指针


这可能比它的价值更麻烦,您可能会更好地重新考虑设计。

我同意@DavidSchwartz的观点,这是一个糟糕的设计,但还有另一个原因

通过使用数组而不是列表,并确保ClientHolder是一个没有外部指针的平面数据结构,您可以处理分段错误

但是,您将如何更新该阵列?比如添加/删除元素?您将需要某种可能会否定共享内存好处的同步


一个问题:为什么你的服务器不能处理这个列表框?

我同意@DavidSchwartz的说法,这是一个糟糕的设计,但还有另一个原因

通过使用数组而不是列表,并确保ClientHolder是一个没有外部指针的平面数据结构,您可以处理分段错误

但是,您将如何更新该阵列?比如添加/删除元素?您将需要某种可能会否定共享内存好处的同步


一个问题:为什么您的服务器无法处理该列表框?

您向我们展示的小代码不可能是真正的代码。构造函数有两个变量,都称为Clients,看起来它试图将std::list分配给std::list*类型的变量。而且,这两个变量都称为Clients,因此Clients=Clients;没有做任何事情。静态_转换到std::list似乎不安全。这是C的一个工件,但在C++中不是一个好方法,因为您正在使用std::list的默认分配器。它不会从您的共享内存部分分配所需的内容,即使分配了,您仍然会遇到麻烦,因为共享内存指针可能会在每个进程中从不同的虚拟地址开始,而这甚至不是寻址锁定。您可能想看看这个答案:Boost.Interprocess允许在共享内存和内存映射文件中创建复杂对象。例如,我们可以在共享内存中构造类似STL的容器。要做到这一点,我们只需要创建一个特殊的托管共享内存段,声明一个Boost.Interprocess分配器,并在共享内存中构造向量(只要它是任何其他对象)。与其使用共享内存,不如使用观察者模式。当客户端连接时,服务器会向主应用程序发送通知,其中包含有关客户端的信息
你可以使用IPC或任何形式的TCP来传递这些信息。如果你真的喜欢共享内存,另一个选择是使用像reddis这样的键值存储来存储客户端信息,并让你的主应用程序订阅数据库来检索新的客户端。你给我们展示的小代码不是真正的代码。构造函数有两个变量,都称为Clients,看起来它试图将std::list分配给std::list*类型的变量。而且,这两个变量都称为Clients,因此Clients=Clients;没有做任何事情。静态_转换到std::list似乎不安全。这是C的一个工件,但在C++中不是一个好方法,因为您正在使用std::list的默认分配器。它不会从您的共享内存部分分配所需的内容,即使分配了,您仍然会遇到麻烦,因为共享内存指针可能会在每个进程中从不同的虚拟地址开始,而这甚至不是寻址锁定。您可能想看看这个答案:Boost.Interprocess允许在共享内存和内存映射文件中创建复杂对象。例如,我们可以在共享内存中构造类似STL的容器。要做到这一点,我们只需要创建一个特殊的托管共享内存段,声明一个Boost.Interprocess分配器,并在共享内存中构造向量(只要它是任何其他对象)。与其使用共享内存,不如使用观察者模式。当客户端连接时,服务器会向主应用程序发送通知,其中包含有关客户端的信息可能只是一个ID。您可以使用IPC或任何形式的TCP来传递此信息。如果您确实喜欢共享内存,另一种选择是使用诸如reddis之类的键值存储来存储客户端信息,并让您的主应用程序订阅数据库以检索新客户端。在发布的代码中,似乎正在复制列表Server newServer*Clients;,那么,这不会绕过您强调的问题吗?正如您所看到的,服务器通过value@smac89不,不会的。当复制列表时,将为该副本分配新内存,并且它不会从共享内存中出来,因为列表只是使用调用new的默认分配器构造的,该分配器可能调用malloc。他必须修改std::list分配器以从共享内存进行分配,否则对象将包含指向非共享内存的指针。在发布的代码中,列表似乎正在复制到服务器newServer*客户端;,那么,这不会绕过您强调的问题吗?正如您所看到的,服务器通过value@smac89不,不会的。当复制列表时,将为该副本分配新内存,并且它不会从共享内存中出来,因为列表只是使用调用new的默认分配器构造的,该分配器可能调用malloc。他必须修改std::list分配器以从共享内存进行分配,否则对象将包含指向非共享内存的指针。我不同意同步会否定共享内存的好处。@MooingDuck-没有什么可以同意或不同意的-我们不知道共享数据的性质以及如何使用该数据。要点是:服务器可以处理该列表框,而不需要任何子级或父级?process和IPCI不同意同步会否定共享内存的好处。@MooingDuck-没有什么可以同意或不同意的-我们不知道共享数据的性质,以及如何使用这些数据。要点是:服务器可以处理该列表框,而不需要任何子级或父级?工艺与工控机
std::list<ClientHolder> *Clients = static_cast<std::list<ClientHolder>*>(mmap(NULL, (pagesize*(1 << 20)),
            PROT_READ | PROT_WRITE,
            MAP_SHARED | MAP_ANONYMOUS, 0, 0));