我的任务是为分布式应用程序(在一台计算机上运行的多个进程,尚未物理分布式)设计一个新界面,该应用程序由许多用 C++/OpenGL 编写的图形面板模块和一个用 Ada 编写的单个模块组成。
这些模块共享参数形式的信息(标量非结构化信息,例如:整数、字符串、浮点数等)。我打算设计一个基于异步套接字的组件(以下称为“接口组件”或 IC),由基于 Boost::Asio 库的每个模块与两个简单的“客户端”原语链接:
Put([ParameterName], [DestinationModule], [Payload], [Type])
Get([ParameterName], [Sourcemodule], [Payload])
ParameterName:指定唯一的参数名称
DestinationModule/SourceModule:寻址系统中的模块
有效负载:实际数据
类型:标识传递参数类型的字符串或值
这些原语中的每一个都在服务器端由两个相应的函数(在 IC 上)处理:
//No function parameters shown here as I don't know
//exactly how I'm going to do this
ProcessPutRequest()
ProcessGetRequest()
由于传入命令的处理将由 IC 启动,因此我打算使用将传递给上述函数的函数处理程序。这样,负责每个模块的每个程序员都可以处理传入的命令并对自己的代码执行必要的类型转换。
问题是……这在 Ada 中可能吗?我知道可以在 C++ 中导入函数并从 Ada 程序中调用它,但是是否可以将函数处理程序从 Ada 传递到 C++ 组件?
(一个附带问题是:您对实现此接口的更好方法有什么建议吗?)
I have this task of designing a new interface for a distributed application (multiple processes running on a single computer, not physically distributed - yet) which is comprised of many graphical panel modules written in C++/OpenGL and a single module written in Ada.
The modules share information on the form of parameters (pieces of scalar non-structured information e.g.: ints, strings, floats, etc...). I intend to design an asynchronous socket based component (which I'll call hereafter 'Interface Component' or IC) to be linked by each module based on Boost::Asio library with two simple 'client' primitives:
Put([ParameterName], [DestinationModule], [Payload], [Type])
Get([ParameterName], [Sourcemodule], [Payload])
ParameterName: Designates a unique parameter name
DestinationModule/SourceModule: Addresses a module in the system
Payload: Actual data
Type: string or value that identifies the type of the passed parameter
Each of these primitives are treated on the server-side by two corresponding functions (on the IC):
//No function parameters shown here as I don't know
//exactly how I'm going to do this
ProcessPutRequest()
ProcessGetRequest()
Because the processing of incoming commands will be started by the IC, I intend to use function handlers which will be passed to the functions above. This way each programmer responsible by each module can process incoming commands and perform the necessary type conversions on his own code.
The question is... is this possible in Ada? I know one can import functions in C++ and call it from Ada programs btu is it possible to pass function handlers from Ada to a C++ component?
(a side-question is: do you have any suggestion of a better way of implementing this interface?)
发布评论
评论(5)
在这两种语言中,编写基于套接字的通信都很简单,尤其是对于只需要传递标量值的接口而言。
为模块创建单独的适合语言的组件将比尝试实现这种混合语言接口和链接工作更加容易和快捷。不要误会我的意思,这是可以做到的,但我需要一个令人信服的理由让我走这条路,而不是编写单独的、简单的套接字数据处理接口。
Coding up socket-based communications is straightforward in both languages, especially so for an interface that needs to pass only scalar values.
Creating separate language-appropriate components for the modules will be far easier and quicker than trying to get this kind of mixed-language interfacing and linking working. Don't get me wrong, that can be done, but I would require a compelling reason to get me to go that way, versus coding up separate, simple socket data processing interfaces.
不确定 Get() 的语义是什么。是否等待新数据?返回最后收到的数据? (在这种情况下,如果尚未收到数据会发生什么?)
假设回调方案和 Ada 2005,您可能会首先考虑一个规范,就像
我假设 IC 将组织编组和注册回调列表一样。
需要注意的一点是:在此方案中,Receiver 过程是在外部(非 Ada)线程的上下文中调用的,这可能会导致 Ada 运行时的任务支持出现问题。假设您使用的是 GNAT,您应该查看
GNAT.Threads
(运行时中的文件g-thread.ads
)。您需要尽快注册线程,例如在执行任何String
操作(例如串联)之前。Not sure what the semantics of
Get()
are. Does it wait for new data? return the last data received? (in which case, what happens if no data has been received yet?)Assuming a callback scheme and Ada 2005, you might for a start consider a spec like
I'm assuming that the IC will organise marshalling and the list of registered callbacks.
One point to be wary of: in this scheme, the Receiver procedure is called in the context of a foreign (non-Ada) thread which may cause problems with the Ada runtime's tasking support. Assuming you're using GNAT, you should look at
GNAT.Threads
(fileg-thread.ads
in the runtime). You need to get the thread registered as soon as possible, for example before doing anyString
operations such as catenation.我不建议构建一个尝试将主要使用 RPC 接口与回调的语言结合起来的接口。这会非常复杂,并且可能会与 Ada 的任务机制产生不良交互。
相反,设计一种将消息从一个组件传递到另一个组件的方法。例如,您可以通过套接字来做到这一点。消息可以是该级别的任何合理大小的数据块。然后,在该工具之上,用 C++ 和 Ada 实现代码,以适合每种语言的方式打包和解包有用的消息。
一旦获得了强大的消息传递接口,您就可以在此基础上构建任何您喜欢的东西。但关键是,您不需要构建任何“调用”另一种语言的东西。
I would not recommend building an interface that tries to combine languages using essentially an RPC interface with callbacks. That will be very complicated and may interact badly with Ada's task mechanism.
Instead, design a method of passing messages from one component to another. You could do this through sockets, for example. A message can be any reasonably sized blob of data at that level. Then, on top of that facility, implement code in each of C++ and Ada that can pack and unpack useful messages in a manner that's appropriate for each language.
Once you've got a robust message-passing interface, you can build anything you like on top of that. But the key is, you won't need to build anything that calls "into" the other language.
关于将 Ada 与 C++ 代码链接,gcc 中有一个开关可以从 .h 和 .h 创建 ada 头文件。 .cpp 和.c 文件: -fdump-ada-规范并且有一个带有警告的操作方法此处。
我的警告:我没有使用过它,只是知道它。
Regarding linking Ada with c++ code, there is a switch in the gcc that creates ada headers from .h & .cpp & .c files : -fdump-ada-spec and there is a howto with caveats here.
My caveat: I have not used it, just know of it.
一般来说,C++ 与其他语言不能很好地兼容。您可能必须告诉双方使用
C
调用约定,这通常不适用于非静态成员函数。因此,无论你想用 Boost 做什么漂亮的体操动作,都可能必须简化为一个简单的 C 风格的接口来与外界对话(在本例中是你的 Ada 代码)。
有一种“模式”可用于执行此类操作。它甚至可能有一个名字,但我不是一个模式专家,所以我不知道它。您要做的就是提供一个静态成员函数,该函数将指向类的指针作为参数,并通过该类指针在内部调用自身。然后,使该静态成员函数(以及要使用的
this
指针)可供外部(非 C++)代码调用。我一直使用它来为操作系统提供类似 C++ 的“回调”例程接口。In general, C++ does not play well with other languages. You will probably have to tell both sides to use the
C
calling convention, which is typically not available for non-static member functions.So whatever nifty class gynmastics you want to do with Boost will probably have to be dumbed down to a simple C-ish interface to talk to the outside world (in this case, your Ada code).
There is sort of a "pattern" available for doing stuff like this. It probably even has a name, but I'm not a pattern guy so I don't know it. What you do is provide a static member function that takes a pointer to the class as a parameter, and internally calls itself through that class pointer. Then you make that static member function (and the
this
pointer you want to use for it) available for the external (non-C++) code to call. I use this all the time to give OS "callback" routines C++-like interfaces.