Added bindNoThread

bindNoThread in conjunction with OnDataAvailable will provide
users with a choice of thread to process requests on. This is
useful when the user relies on single threaded message loop based
design to avoid locking.
diff --git a/include/dap/session.h b/include/dap/session.h
index 52be9f2..e11c57e 100644
--- a/include/dap/session.h
+++ b/include/dap/session.h
@@ -199,6 +199,16 @@
                     const std::shared_ptr<Writer>&) = 0;
   inline void bind(const std::shared_ptr<ReaderWriter>&);
 
+
+  // Alternative to bind() for control over which thread the request is processed.
+  // If bindNoThread is used, the user must call OnDataAvailable() whenever data is
+  // ready in the reader pipe. The processing will be done on the calling thread
+  // and a function to handle the request will be returned in some cases, which can
+  // be executed on any thread of user choice.
+  virtual std::function<void()> OnDataAvailable() = 0;
+  virtual void bindNoThread(const std::shared_ptr<dap::Reader>& r,
+                            const std::shared_ptr<dap::Writer>& w) = 0;
+
  protected:
   using RequestSuccessCallback =
       std::function<void(const TypeInfo*, const void*)>;
diff --git a/src/session.cpp b/src/session.cpp
index c8005dd..f95d095 100644
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -52,6 +52,26 @@
     handlers.put(typeinfo, handler);
   }
 
+  void bindNoThread(const std::shared_ptr<dap::Reader>& r,
+                    const std::shared_ptr<dap::Writer>& w) override {
+    if (isBound.exchange(true)) {
+      handlers.error("Session is already bound!");
+      return;
+    }
+    reader = dap::ContentReader(r);
+    writer = dap::ContentWriter(w);
+  }
+
+  std::function<void()> OnDataAvailable() override {
+    auto request = reader.read();
+    if (request.size() > 0) {
+      if (auto payload = processMessage(request)) {
+        return payload;
+      }
+    }
+    return {};
+  }
+
   void bind(const std::shared_ptr<dap::Reader>& r,
             const std::shared_ptr<dap::Writer>& w) override {
     if (isBound.exchange(true)) {