如何将异步调用转换成同步调用

      上上篇文章演示了如何将异步调用转换为同步调用。本篇文章则演示了反过程。为何我们需要将异步调用转换为同步调用?这往往是为了获得编程的便利性——前文说过异步调用比较反人类。如果底层是异步的,转换为同步一般会损失性能。所以这种做法较少用于服务端,一般用于客户端。
      如果是体位2的异步,很简单,反复查询直到OK即可,两次查询间sleep。一般sleep时间设置为可以容忍的延迟时间。sleep时间短,则响应快(但即使你设置为sleep(0)也不可能每秒抽插超过1000次),但是cpu负载也比较大。注意如果不sleep,cpu将跑满,这可能导致工作线程更慢完成(想象下你让某人做件事,然后在一旁不停地问好了没好了没),最好不要这么做。
===============代码的分割线====================
#include <iostream>
#include <string>
#include <queue>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <windows.h>      //      只用到Sleep函数

using namespace std;

string somefuncMaybeBlock(){
      string str;
      getline(cin, str);
      return str;      //      如果是未采用隐式数据共享的std实现,这句话比较低效,但无妨,此例只是演示体位变换
}
class CheckMeLaterCaller{
public:
      class Result{
      public:
              Result()
                      : ready_flag(false){
              }
              void setData(const string& res){
                      boost::mutex::scoped_lock lock(mtx);
                      result = res;
                      ready_flag = true;
              }
              string getData(){
                      boost::mutex::scoped_lock lock(mtx);
                      return result;
              }
              bool ready(){
                      boost::mutex::scoped_lock lock(mtx);
                      return ready_flag;
              }
      private:
              string result;
              bool ready_flag;
              boost::mutex mtx;
      };
      void call(Result* result){
              boost::mutex::scoped_lock(mtx);
              queue.push(result);
              if (queue.size() == 1){
                      cond.notify_all();
                       
      }
      CheckMeLaterCaller(){
              running_flag = true;
              grp.create_thread(boost::bind(&CheckMeLaterCaller::run, this));
      }
      ~CheckMeLaterCaller(){
              {
                      boost::mutex::scoped_lock lock(mtx);
                      running_flag = false;
                      cond.notify_all();
              }
              grp.join_all();
      }
private:
      void run(){
              while (true){
                      Result* res = NULL;
                      {
                              boost::mutex::scoped_lock lock(mtx);
                              while (running_flag && queue.empty()){
                                      cond.wait(lock);                           
                              }
                              if (!running_flag){
                                      return;
                              }
                              res = queue.front();
                              queue.pop();
                      }
                      if (res){
                              string tmp = somefuncMaybeBlock();
                              res->setData(tmp);
                                       
              }
               
      boost::mutex mtx;
      boost::condition_variable cond;
      std::queue<Result*> queue;
      bool running_flag;
      boost::thread_group grp;
};

#define SOME_DELAY_YOU_CAN_BEAR 10
class BlockAgainCaller{
public:
      BlockAgainCaller(){}

      string call(){ 
            CheckMeLaterCaller::Result res;
            inner.call(&res);
            while (!res.ready()){
                  ::Sleep(SOME_DELAY_YOU_CAN_BEAR);
            }
            return res.getData();
      }
private:
      CheckMeLaterCaller inner;   
};
int main(){
      BlockAgainCaller cal;
      for (int i = 0; i < 5; i ++){
              cout << cal.call() << endl;
      }
      return 0;
}
===============代码的分割线====================
      如果是体位3的异步,做法也很简单,一个bool变量+条件变量即可。下面代码中ProactiveCaller::call是一个异步调用(由somefuncMaybeBlock同步调用转换得到),BlockAgainCaller::call将其再次转换成同步调用。
===============代码的分割线====================
#include <iostream>
#include <string>
#include <queue>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <windows.h>      //      只用到Sleep函数

using namespace std;

string somefuncMaybeBlock(){
      string str;
      getline(cin, str);
      return str;      //      如果是未采用隐式数据共享的std实现,这句话比较低效,但无妨,此例只是演示体位变换
}

class ProactiveCaller{
public:
      class DoneHandler
      {
      public:
            virtual void onFinish(const string& str) = 0;
            virtual ~DoneHandler(){}
      };
      void call(DoneHandler* handler){
            boost::mutex::scoped_lock(mtx);
            queue.push(handler);
            if (queue.size() == 1){
                  cond.notify_all();
                     
         
      ProactiveCaller(){
            running_flag = true;
            grp.create_thread(boost::bind(&ProactiveCaller::run, this));
      }
      ~ProactiveCaller(){
            {
                  boost::mutex::scoped_lock lock(mtx);
                  running_flag = false;
                  cond.notify_all();
            }
            grp.join_all();
      }
private:
      void run(){
            while (true){
                  DoneHandler* handler = NULL;
                  {
                        boost::mutex::scoped_lock lock(mtx);
                        while (running_flag && queue.empty()){
                              cond.wait(lock);                       
                        }
                        if (!running_flag){
                              return;
                        }
                        handler = queue.front();
                        queue.pop();
                  }
                  if (handler){
                        string tmp = somefuncMaybeBlock();
                        handler->onFinish(tmp);
                                 
            }
         
     
      boost::mutex mtx;
      boost::condition_variable cond;
      std::queue<DoneHandler*> queue;
      bool running_flag;
      boost::thread_group grp;     
};

class BlockAgainCaller : public ProactiveCaller::DoneHandler{
public:
      BlockAgainCaller():done_flag(false){}

      string call(){           
            boost::mutex::scoped_lock lock(mtx);
            done_flag = false;           
            inner.call(this);
            while (!done_flag)
            {
                  cond.wait(lock);                 
            }
            return buf;
      }

      virtual void onFinish(const string& str){
            boost::mutex::scoped_lock lock(mtx);
            buf = str;
            done_flag = true;
            cond.notify_all();
      }

private:
      ProactiveCaller inner;
      boost::mutex mtx;
      boost::condition_variable cond;
      std::string buf;
      bool done_flag;
};

int main(){
      BlockAgainCaller cal;
      for (int i = 0; i < 5; i ++){
            cout << cal.call() << endl;
      }
      return 0;
}
===============代码的分割线====================
      体位2的异步转同步简单,但是要注意每秒抽插数能否满足你的要求(小于1000次)。体位3的异步转同步,每秒抽插数的极限就高多了,一般可以达到每秒几十万-百万次这个级别(取决于所使用的条件变量的效率,可以写一个啥都不干的somefuncMaybeBlock试验看看)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值