santazhang / simple-rpc

Simple RPC in C++, with Python binding
http://www.yzhang.net/simple-rpc/
BSD 3-Clause "New" or "Revised" License
27 stars 6 forks source link

Add Callback mechanism #1

Closed visualzhou closed 11 years ago

visualzhou commented 11 years ago

To make writing callback easier, the Callback templates are introduced and makeCallable() is handy to bind functions to objects. Here is an example. https://github.com/visualzhou/simple-rpc/blob/callback/test/callback_test.cc#L85

  rpc::Runnable* cb = makeCallable(&Counter::inc, &c); // Bind function to object.
  pool->run_async(cb); // cb is deleted after running by pool.

More examples could be found in that test file.

The best thing is currying. It is demonstrated in https://github.com/visualzhou/simple-rpc/blob/callback/test/demo_client.cc Here is the function declared.

class CallbackHanler {
public:
    void onCallback(Client* cl, int* rpc_counter, Future* fu) { ... }
}

Call makeCallable() to get a FutureCallback.

    CallbackHanler handler; // Thread-safe
    for (int i = 0; i < concurrency; i++) {
        FutureAttr attr;
        attr.callback = makeCallable(&CallbackHanler::onCallback, &handler, cl, &rpc_counter);
        // Start the endless chains of callbacks until close_and_release.
        Future* fu = MathProxy(cl).async_is_prime(rand(), attr);
        if (fu != NULL) {
            fu->release();
        }
    }

Now the Runnable and FutureCallback are just typedef and their interfaces are kept the same as before. All the code we have now still work.

typedef Callback<void> Runnable;
typedef Callback<void, Future*> FutureCallback;

Notice we need to wrap all logic in classes and have its object before using it. This is reasonable because all logic is organized together instead of spreading all around. Image the change when writing coordinators in Lynx and throughout tests.