C 用于管理加载到内存中的共享库的设计模式
你好, 我正在开发一个大型项目,其中将包含我将开发的两个模块(共享库) 这些模块是我用C语言创建的共享库,它们必须相互同步和交换消息 管理器模块将控制并将这两个模块(.so)加载到内存中。如果一个人失败了。经理可以尝试重新加载它 我想知道这是我第一次做这样的事情。是否有可以遵循的设计模式 所有这些都将用C编写,并使用APR(ApachePortableRuntime)进行内存池管理,如果需要,还可以使用一些线程池C 用于管理加载到内存中的共享库的设计模式,c,design-patterns,C,Design Patterns,你好, 我正在开发一个大型项目,其中将包含我将开发的两个模块(共享库) 这些模块是我用C语言创建的共享库,它们必须相互同步和交换消息 管理器模块将控制并将这两个模块(.so)加载到内存中。如果一个人失败了。经理可以尝试重新加载它 我想知道这是我第一次做这样的事情。是否有可以遵循的设计模式 所有这些都将用C编写,并使用APR(ApachePortableRuntime)进行内存池管理,如果需要,还可以使用一些线程池 启动将加载两个模块的管理器 然后,Manager调用它们两个上的一些函数来启动和
- 决定线程模型
- 您的模块将使用它们控制的内存或管理器交换信息吗
- 模块是否应等待它们之间共享的条件变量或由管理者拥有的条件变量
- 决定你需要一个多普通的经理
- 它应该能够轮询模块目录还是读取配置,或者两者兼而有之
- 如果管理器管理消息,模块之间的信令需要什么
fork()
为每个模块加载一次管理器;例如,这就是chrome插件API使用的模型
此外,处理组件故障本身可能非常非常棘手。仅仅因为A重新启动并不意味着B准备好与新重新启动的A对话。您可能想尝试收集一些想法,通过鼓励将应用程序分解为消息传递子组件(具有管理器模块的层次结构)来重新启动失败的组件,这样可以非常好地处理组件故障。如果您只有两个模块,这可能有点过分,但至少需要考虑一下
至于如何沟通,有许多范例。如果这些模块处于相同的过程中,您可以传递一个vtable。例如:
gcc (GCC) 4.7.2
您的管理器将加载这两个变量,将vtable从A传递到B,反之亦然,然后调用start例程。订购时要小心——要么A必须在B准备好之前启动,要么B准备好之前启动,反之亦然,他们需要对此表示同意
如果它们在独立的进程中,消息传递通常是一种方式。在这一点上,它本质上是一个网络协议——您的子流程将向管理器发送序列化消息,管理器将它们路由到其他子流程。对话可能有点像这样:
// 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();
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!"
请记住,除了上面的示例之外,还有许多其他方法可以构造此类协议,并在消息传递协议的基础上构建RPC。你可能对一些东西感兴趣,比如(你可以直接使用!),或者,以前做过类似的事情。在这类协议之上的其他优化包括使用管理器在a和B之间建立某种直接通道,并且仅当a或B需要重新启动时,才再次涉及到它
也就是说,在你弄清楚经理需要做什么之前,不要深入了解经理的工作细节。设计了pluginmanager的高级接口和pluginplugin协议;然后才设计pluginmanager接口的细节。它很容易偏离正轨,最终导致像或这样的复杂情况。我明白了,你需要将第1点和第2点解耦
- 为此,您应该有一个名为BootstrapManager的单独类,它将 负责加载模块并在模块出现故障时重新加载李>
- 接下来您需要一个名为Module的抽象类,它有3个
方法,
start()-启动模块, 停止()-停止模块, cleanUp()-清理活动, 通信()-与另一个模块通信 - 现在模块1和模块2都将扩展这个类并实现 相应地,他们自己的业务逻辑
// 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();
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!"
handler1.c
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
#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);
}
#include <stdio.h>
void print_hello_from_handler2()
{
printf("hello world from handler2\n");
}
#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);
}
char *string_from_lib2="message from lib2 variable";
char *str="message from lib2 method1";
char *get_message_from_lib2_method1()
{
return str;
}
lib2_file1.c
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
#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);
}
#include <stdio.h>
void print_hello_from_handler2()
{
printf("hello world from handler2\n");
}
#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);
}
char *string_from_lib2="message from lib2 variable";
char *str="message from lib2 method1";
char *get_message_from_lib2_method1()
{
return str;
}
lib2_file2.c
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
#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);
}
#include <stdio.h>
void print_hello_from_handler2()
{
printf("hello world from handler2\n");
}
#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);
}
char *string_from_lib2="message from lib2 variable";
char *str="message from lib2 method1";
char *get_message_from_lib2_method1()
{
return str;
}
lib2.h
#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");
}
extern char *string_from_lib1;
char *get_message_from_lib1_method1();
void get_message_from_lib1_method2(char **s);
extern char *string_from_lib2;
char *get_message_from_lib2_method1();
void get_message_from_lib2_method2(char **s);
handler2.h
#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");
}
extern char *string_from_lib1;
char *get_message_from_lib1_method1();
void get_message_from_lib1_method2(char **s);
extern char *string_from_lib2;
char *get_message_from_lib2_method1();
void get_message_from_lib2_method2(char **s);
Makefile
void print_hello_from_handler2();
然后安装二进制文件和库
linux$ cd src
linux$ make
要清理已安装的库和二进制文件,以及清理生成二进制文件库和对象,请执行以下操作:
linux$ sudo make install
要运行应用程序,请执行以下操作:
linux$ sudo make clean
如果您已经决定使用APR,您可能应该使用 这个你可以找到一个教程
.这里的体系结构相对简单,因此您不需要复杂的设计模式 主要问题是数据完整性。如果系统部分崩溃,如何确保两者具有相同的数据副本 由于您正在使用消息传递,您已经解决了一半的问题。你