On the client side, an engine runs in its own thread, and takes care of receiving and processing data objects from its corresponding manager on the server. A work engine, for example, would take care of getting work data from the work manager, executing the work, and requesting more work when it's done. Data objects are generally polymorphic and know how to process themselves. To execute the work, a work engine passes the work data a pointer to itself, and calls the work data's process() method. The work data will compute itself, using the work engine to communicate with the work manager, if desired. Both the engine and the data have associated GUI objects which can be used for user interface. The engine and the GUIs are all contained in a chassis object, which can be an applet or application.
On the server side, an advocate object serves as the engine's representative and forwards the engine's calls to the manager. The manager has access to several data pools. These pools may be shared by other managers serving other purposes. In Fig.1, for example, the work and result pools are shared by the work and watch managers, allowing the watch manager to watch the progress of the computation and inform watch engines of such things as new results and statistics. The whole set of associated managers and data pools compose a problem. There may be many independent problems existing in a server at the same time. A problem table keeps track of these, and can be used by volunteers to choose the problem they want to participate in.