用于管理加载到内存中的共享库的设计模式

ant*_*009 3 c design-patterns

gcc (GCC) 4.7.2
Run Code Online (Sandbox Code Playgroud)

你好,

我正在开发一个大项目,它将包含我将开发的2个模块(共享库).

这些模块是我在C中创建的共享库,它们必须在彼此之间同步和交换消息.

在此输入图像描述

管理器模块将控制这两个模块(.so)并将其加载到内存中.如果一个人失败了.经理可以尝试重新加载它.

我想知道这是我第一次做这样的事情.是否有可以遵循的设计模式?

所有这些都将用C语言编写并使用APR(Apache Portable Runtime)进行内存池管理,如果需要可能还有一些线程池.

  1. 启动管理器,将加载两个模块.
  2. 然后管理器调用它们上的一些函数可能启动和停止它们,并可能进行清理.
  3. 一旦两个模块都已加载并启动.他们应该能够在彼此之间交换一些消息.

这些模块都将在运行Redhat的同一台机器上运行.

非常感谢任何建议.

bdo*_*lan 11

管理器模块将控制这两个模块(.so)并将其加载到内存中.如果一个人失败了.经理可以尝试重新加载它.

如果它在单个C进程中,这通常是一个坏主意 - 如果其中一个模块发生故障,您不太可能安全地卸载它,更不用说再次加载它.如果您需要能够从模块故障中恢复,则必须使用独立进程.代码仍然可以在.so文件中 - 只fork()需要管理器一次就可以加载每个模块; 例如,这是chrome plugins API使用的模型.

而且,处理组件故障本身就非常非常棘手.仅仅因为重新启动并不意味着B已准备好与新重新启动的A进行通信.您可能希望尝试从erlang中收集一些想法,通过鼓励将应用程序分解为带有消息传递的子组件,可以非常好地处理组件故障.管理程序模块的层次结构以重新启动故障组件.如果你只有两个模块,这可能有点矫枉过正,但至少要考虑一下.

至于如何沟通,有许多范例.如果这些模块在同一个过程中,你可以只传递一个vtable.也就是说,例如:

// moduleA.h

struct vtable_A {
  void (*do_something)();
};

void set_vtable_B(struct vtable_B *);
struct vtable_A *get_vtable_A();
void start_A();

// moduleB.h
struct vtable_B {
  void (*do_something)();
};

void set_vtable_A(struct vtable_A *);
struct vtable_B *get_vtable_B();
void start_B();
Run Code Online (Sandbox Code Playgroud)

您的经理将加载两者,将vtable从A传递给B,反之亦然,然后调用启动例程.小心订购 - 要么必须在B准备好之前启动A,要么反之亦然,他们需要对此有所帮助.

如果它们处于独立进程中,则通常可以通过消息传递.它本质上是一个网络协议 - 您的子进程将序列化消息发送给管理器,管理器将它们路由到其他子进程.谈话可能看起来像这样:

MGR->A      START
MGR->B      START
A->MGR      REGISTER_ENDPOINT 'ProcessA'
A->MGR      WATCH_ENDPOINT 'ProcessB'
MGR->A      OK_REGISTER 'ProcessA'
MGR->A      OK_WATCH 'ProcessB'
B->MGR      REGISTER_ENDPOINT 'ProcessB'
B->MGR      WATCH_ENDPOINT 'ProcessA'
MGR->B      OK_REGISTER 'ProcessB'
MGR->A      NEW_ENDPOINT 'ProcessB'
A->MGR      APPLICATION_DATA TO:'ProcessB', PAYLOAD:"Hello, world!"
MGR->B      OK_WATCH 'ProcessA'
MGR->B      NEW_ENDPOINT 'ProcessA'
MGR->B      APPLICATION_DATA FROM:'ProcessA', PAYLOAD:"Hello, world!"
Run Code Online (Sandbox Code Playgroud)

请记住,除了上面的示例之外,还有许多其他方法可以构建这种协议,并在消息传递协议之上构建RPC.您可能有兴趣查看诸如DBUS(您可以直接使用它)或DCOM之类的东西,它们之前已经完成了这类工作.除此类协议之外的其他优化包括使用管理器在A和B之间建立某种直接通道,并且只有在需要重新启动A或B时再次使用它.

也就是说,在弄清楚需要做什么之前,不要过于深入了解经理如何运作的细节.设计插件< - >管理器高级接口,插件< - >插件协议; 然后才设计插件< - >管理器界面的细节.它很容易被引入,并最终变得像CORBASOAP那样过于复杂.


MOH*_*MED 5

在您的请求中基于项目的简单示例之后:

您的源代码的体系结构可能是这样的:

src
   |__handler1.c //containing the main function
   |__handler2.c //containing other functions
   |__lib1.c //containing lib1 source
   |__lib2_file1.c  //containing lib2 source
   |__lib2_file2.c  //containing lib2 source
   |__Makefile  // file which contains commands to build the project
   |__inc
         |__lib1.h
         |__lib2.h
         |__handler2.h
Run Code Online (Sandbox Code Playgroud)

handler1.c

#include <stdio.h>
#include "lib1.h"
#include "lib2.h"
#include "handler2.h"

int main()
{
    char *s1, *s2;
    print_hello_from_handler2();
    s1 = get_message_from_lib1_method1();
    get_message_from_lib1_method2(&s2);

    printf("s1 = %s\n",s1);
    printf("s2 = %s\n",s2);
    printf("extern string_from_lib1 = %s\n",string_from_lib1);
    printf("extern string_from_lib2 = %s\n",string_from_lib2);
}
Run Code Online (Sandbox Code Playgroud)

handler2.c

#include <stdio.h>

void print_hello_from_handler2()
{
    printf("hello world from handler2\n");
}
Run Code Online (Sandbox Code Playgroud)

lib1.c

#include "lib2.h"
char *string_from_lib1="message from lib1 variable";

char *get_message_from_lib1_method1()
{
    return get_message_from_lib2_method1();
}

void get_message_from_lib1_method2(char **s)
{
    get_message_from_lib2_method2(s);
}
Run Code Online (Sandbox Code Playgroud)

lib2_file1.c

char *string_from_lib2="message from lib2 variable";

char *str="message from lib2 method1";

char *get_message_from_lib2_method1()
{
    return str;
}
Run Code Online (Sandbox Code Playgroud)

lib2_file2.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void get_message_from_lib2_method2(char **s)
{
    *s = malloc(30);
    strcpy(*s,"message from lib2 method2");
}
Run Code Online (Sandbox Code Playgroud)

lib1.h

extern char *string_from_lib1;

char *get_message_from_lib1_method1();
void get_message_from_lib1_method2(char **s);
Run Code Online (Sandbox Code Playgroud)

lib2.h

extern char *string_from_lib2;

char *get_message_from_lib2_method1();
void get_message_from_lib2_method2(char **s);
Run Code Online (Sandbox Code Playgroud)

handler2.h

void print_hello_from_handler2();
Run Code Online (Sandbox Code Playgroud)

Makefile文件

SHLIB_EXT=so
LINK=$(CC)
SHLIB1_FILE=libmodule1.$(SHLIB_EXT).1
SHLIB2_FILE=libmodule2.$(SHLIB_EXT).1
SHLIB1_FLAGS=-shared -Wl,-soname,$(SHLIB1_FILE)
SHLIB2_FLAGS=-shared -Wl,-soname,$(SHLIB2_FILE)
FPIC=-fPIC

all: libmodule2.$(SHLIB_EXT) libmodule1.$(SHLIB_EXT) handler


%.o: %.c
    $(CC) -Iinc -c -o $@ $^

handler: handler1.o handler2.o
    $(CC) -o $@ $^ -L. -lmodule2 -lmodule1

lib2_file1.o: lib2_file1.c
    $(CC) $(FPIC) -Iinc -c -o $@ $<

lib2_file2.o: lib2_file2.c
    $(CC) $(FPIC) -Iinc -c -o $@ $<

libmodule2.$(SHLIB_EXT): lib2_file1.o lib2_file2.o
    $(LINK) $(SHLIB2_FLAGS) -o $(SHLIB2_FILE) $^
    ln -sf $(SHLIB2_FILE) $@

libmodule1.o: lib1.c
    $(CC) $(FPIC) -Iinc -c -o $@ $<

libmodule1.$(SHLIB_EXT): libmodule1.o
    $(LINK) $(SHLIB1_FLAGS) -o $(SHLIB1_FILE) $< -L. -lmodule2
    ln -sf $(SHLIB1_FILE) $@


clean:
    rm -f *.o *.so* handler
    rm -f /usr/lib/$(SHLIB1_FILE)
    rm -f /usr/lib/$(SHLIB2_FILE)
    rm -f /usr/lib/libmodule1.$(SHLIB_EXT)
    rm -f /usr/lib/libmodule2.$(SHLIB_EXT)

install:
    cp $(SHLIB1_FILE) /usr/lib/
    cp $(SHLIB2_FILE) /usr/lib/
    cp handler /usr/bin/
    ln -sf /usr/lib/$(SHLIB1_FILE) /usr/lib/libmodule1.$(SHLIB_EXT)
    ln -sf /usr/lib/$(SHLIB2_FILE) /usr/lib/libmodule2.$(SHLIB_EXT)
Run Code Online (Sandbox Code Playgroud)

编译项目的命令

linux$ cd src
linux$ make
Run Code Online (Sandbox Code Playgroud)

然后安装二进制文件和库

linux$ sudo make install
Run Code Online (Sandbox Code Playgroud)

清理已安装的库和二进制文件并清理构建二进制库和对象:

linux$ sudo make clean
Run Code Online (Sandbox Code Playgroud)

要运行该应用程序:

linux$ handler
hello world from handler2
s1 = message from lib2 method1
s2 = message from lib2 method2
extern string_from_lib1 = message from lib1 variable
extern string_from_lib2 = message from lib2 variable
linux$
Run Code Online (Sandbox Code Playgroud)