qicosmos / rest_rpc

modern C++(C++11), simple, easy to use rpc framework
MIT License
1.66k stars 365 forks source link

关于write_queue_为什么要加锁的小疑问 #98

Closed JustDoIt0910 closed 1 year ago

JustDoIt0910 commented 1 year ago

您好,想请教一下,如果按照现在的实现,server端connection的response()方法和发送数据包完成处理器on_write()应该都是在同一个线程,也就是connection所属的io线程调用的吧?这个write_queue为什么需要加锁呢,是不是考虑以后有可能在线程池中执行router.route()?

qicosmos commented 1 year ago

这个response 可能在用户的启动的一个线程里去response的,和io 线程不是同一个线程,需要保证线程安全。可以参考example 里async_echo例子

JustDoIt0910 commented 1 year ago

懂了,感谢。另外有个想法不知道可不可行。能不能另外开一个业务线程池,在invoker::apply中判断一下mode, 是Async的话,将call和response包装成一个lambda丢到线程池里,这样是不是就不用用户负责response了:

template<ExecMode model>
                static inline void apply(const Function &func,
                                         std::weak_ptr<connection> conn, const char *data,
                                         size_t size, std::string &result,
                                         ExecMode &exe_model)
                {
                    using args_tuple = typename function_traits<Function>::bare_tuple_type;
                    exe_model = ExecMode::sync;
                    msgpack_codec codec;
                    try
                    {
                        auto tp = codec.unpack<args_tuple>(data, size);
                        //pseudo-code
                        if(is Async mode)
                        {
                            workerThreadPool_->execute([](){
                                call();
                                response();
                            })
                        }
                        else
                            call(func, conn, result, std::move(tp));
                        exe_model = model;
                    }
                    catch (std::invalid_argument &e)
                    {
                        result = codec.pack_args_str(result_code::FAIL, e.what());
                    }
                    catch (const std::exception &e)
                    {
                        result = codec.pack_args_str(result_code::FAIL, e.what());
                    }
                }
qicosmos commented 1 year ago

这样也有问题,比如丢到线程池里执行用户函数,这个用户函数又启动了一个线程,它其实希望是在它的线程里response,这时候框架已经response了。