Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi-threaded http program will enter task.wait() and wait for std::unique_lock<std::mutex> then can't quit #1170

Closed
yyzhang123 opened this issue Jul 3, 2019 · 5 comments

Comments

@yyzhang123
Copy link

I recently used cpprest sdk on the centos7.4 operating system to develop a multi-threaded http server and client program, but found that the program tasks often enters wait() and can't quit, is it where I used it wrong?my main code is as follows :
first, I set the receive and send timeouts via http_listener_config like following:
http server side:

http_listener_config listenconfig;
listenconfig.set_timeout(utility::seconds(3));
HttpServerBase(utility::string_t url, http_listener_config& listenconfig, std::string reqcmdid, eRedisListKey redislistkey, RedisConnectPool* connpool, eMapType reqcmdtype, bool bsyncprocess = false)
:m_Listener(url, listenconfig)
{
m_RedisConnPool = std::move(connpool);

                  m_ReqCommandId = std::move(reqcmdid);

                  m_RedisListKey = std::move(redislistkey);

                  m_SyncProcess = bsyncprocess;
                 
                  m_ReqCmdMapType =  std::move(reqcmdtype);
                 
                  m_Listener.support(methods::POST, std::bind(&HttpServerBase::Handle_Process_Json, this, std::placeholders::_1));
                  SPDLOG_DEBUG("create HttpServerBase succeed listener url:{}, m_ReqCommandId:{}, m_RedisListKey:{}, m_SyncProcess:{}", url, m_ReqCommandId, m_RedisListKey, m_SyncProcess);

};

//json parse
virtual void Handle_Process_Json(http_request message)
{
try
{
SPDLOG_DEBUG("recv request:{} from remote_address:{}, command:{}", http::uri::decode(message.to_string()), message.remote_address(), m_ReqCommandId);

                              auto parsetask = message.extract_json().then([&](pplx::task<json::value> previousTask)
                              {
                                          try  
                                          { 
                                                      SPDLOG_DEBUG("after extract_json");
                                                      const json::value& cjsonreq = previousTask.get();
                                                      SPDLOG_DEBUG("after previousTask.get()");
                                                      message.reply(status_codes::OK);
                                          } 
                                          catch (const std::exception& sysexp)
                                          {
                                                      SPDLOG_ERROR("occured std::exception:{} when recv:{}", sysexp.what(), m_ReqCommandId);
                                          }
                              }).wait();
                  }
                  catch (const std::exception& sysexp)
                  {
                              SPDLOG_ERROR("occured std::exception:{} when recv:{}", sysexp.what(), m_ReqCommandId);
                  }
                  catch(...)
                  {
                              SPDLOG_ERROR("occured exception");
                  }
      };

http client side:
//first param is desturl
//second param is request's timeout
HttpClientBase(utility::string_t desturl, std::chrono::microseconds timeout)
{
uri_builder builder(desturl);
m_http_client_config.set_timeout(timeout);
m_http_client = new http_client(builder.to_uri().to_string(), m_http_client_config);
};

  virtual void SendRequest(const method& mtd, const utility::string_t& path_query_fragment, const json::value& req_body_data)
 {
    try
    {
        m_http_client->request(mtd, path_query_fragment, req_body_data).then([=](pplx::task<http_response> task)
        {
            try  
            {
                //parse response
                http_response response = task.get();
				SPDLOG_DEBUG("recv response msg from media that rspcode is {}", response.status_code());
                if(response.status_code() == status_codes::OK)
                {
                    auto rspbody = response.extract_json().get();
                    if(rspbody.is_null())
                    {
                        SPDLOG_ERROR("rspbody is NULL in ProcessMediaInfo::SendRequest");
                        return ;
                    }
                    processjson(rspbody);
                }
            }  
            catch (const http_exception& e)  
            {  
                 SPDLOG_ERROR("occured http_exception:{}, errorcode:{} in ProcessMediaInfo::SendRequest body:{}", e.what(), e.error_code().message(), req_body_data.serialize());
            } 
        });
    }
    catch (const std::exception& sysexp)
    {
        SPDLOG_ERROR("occured std::exception:{} in ProcessMediaInfo::SendRequest", sysexp.what());
    }

Does this cpprest sdk support the centos7.4 operating system? Why is this?I found that after the program runs for a while, multiple threads will enter each other and wait for each other to compete with std::unique_lock and can't quit, When this happens, httpserver will not be able to receive new messages. The thread stack information is as follows:

Thread 49 (Thread 0x7fedb7e42700 (LWP 7836)):
#0 0x00007fedbbec8965 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1 0x00007fedbc18a82c in std::condition_variable::wait(std::unique_lockstd::mutex&) () from /lib64/libstdc++.so.6
#2 0x000000000042be6d in pplx::details::_Task_impl_base::_Wait() ()
#3 0x000000000045a694 in std::_Function_handler<void (pplx::taskweb::http::http_response), ProcessMediaInfo::SendRequest(std::string const&, std::string const&, web::json::value const&)::{lambda(pplx::taskweb::http::http_response)#1}>::_M_invoke(std::_Any_data const&, pplx::taskweb::http::http_response) ()
#4 0x00000000004268ef in std::_Function_handler<unsigned char (pplx::taskweb::http::http_response), std::function<unsigned char (pplx::taskweb::http::http_response)> pplx::details::_MakeTToUnitFunc<pplx::taskweb::http::http_response >(std::function<void (pplx::taskweb::http::http_response)> const&)::{lambda(pplx::taskweb::http::http_response)#1}>::_M_invoke(std::_Any_data const&, pplx::taskweb::http::http_response) ()
#5 0x0000000000461c37 in std::function<unsigned char (pplx::taskweb::http::http_response)>::operator()(pplx::taskweb::http::http_response) const ()
#6 0x0000000000461d20 in pplx::details::_PPLTaskHandle<unsigned char, pplx::taskweb::http::http_response::_ContinuationTaskHandle<web::http::http_response, void, ProcessMediaInfo::SendRequest(std::string const&, std::string const&, web::json::value const&)::{lambda(pplx::taskweb::http::http_response)#1}, std::integral_constant<bool, true>, pplx::details::_TypeSelectorNoAsync>, pplx::details::_ContinuationTaskHandleBase>::invoke() const ()
#7 0x000000000041919f in pplx::details::_TaskProcHandle::_RunChoreBridge(void*) ()
#8 0x00000000004ac3fe in boost::asio::detail::completion_handler<boost::_bi::bind_t<void, void ()(void), boost::_bi::list1<boost::_bi::value<void*> > > >::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) ()
#9 0x00000000004ae9d0 in boost::asio::detail::scheduler::run(boost::system::error_code&) ()
#10 0x00000000004acdc6 in boost::asio::detail::posix_thread::func<(anonymous namespace)::threadpool_impl::add_thread()::{lambda()#1}>::run() ()
#11 0x00000000004ad4bf in boost_asio_detail_posix_thread_function ()
#12 0x00007fedbbec4dd5 in start_thread () from /lib64/libpthread.so.0
#13 0x00007fedbb6d5ead in clone () from /lib64/libc.so.6
Thread 48 (Thread 0x7fedb7641700 (LWP 7837)):
#0 0x00007fedbbec8965 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1 0x00007fedbc18a82c in std::condition_variable::wait(std::unique_lockstd::mutex&) () from /lib64/libstdc++.so.6
#2 0x000000000042be6d in pplx::details::_Task_impl_base::_Wait() ()
#3 0x000000000045a694 in std::_Function_handler<void (pplx::taskweb::http::http_response), ProcessMediaInfo::SendRequest(std::string const&, std::string const&, web::json::value const&)::{lambda(pplx::taskweb::http::http_response)#1}>::_M_invoke(std::_Any_data const&, pplx::taskweb::http::http_response) ()
#4 0x00000000004268ef in std::_Function_handler<unsigned char (pplx::taskweb::http::http_response), std::function<unsigned char (pplx::taskweb::http::http_response)> pplx::details::_MakeTToUnitFunc<pplx::taskweb::http::http_response >(std::function<void (pplx::taskweb::http::http_response)> const&)::{lambda(pplx::taskweb::http::http_response)#1}>::_M_invoke(std::_Any_data const&, pplx::taskweb::http::http_response) ()
#5 0x0000000000461c37 in std::function<unsigned char (pplx::taskweb::http::http_response)>::operator()(pplx::taskweb::http::http_response) const ()
#6 0x0000000000461d20 in pplx::details::_PPLTaskHandle<unsigned char, pplx::taskweb::http::http_response::_ContinuationTaskHandle<web::http::http_response, void, ProcessMediaInfo::SendRequest(std::string const&, std::string const&, web::json::value const&)::{lambda(pplx::taskweb::http::http_response)#1}, std::integral_constant<bool, true>, pplx::details::_TypeSelectorNoAsync>, pplx::details::_ContinuationTaskHandleBase>::invoke() const ()
#7 0x000000000041919f in pplx::details::_TaskProcHandle::_RunChoreBridge(void*) ()
#8 0x00000000004ac3fe in boost::asio::detail::completion_handler<boost::_bi::bind_t<void, void ()(void), boost::_bi::list1<boost::_bi::value<void*> > > >::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) ()
#9 0x00000000004ae9d0 in boost::asio::detail::scheduler::run(boost::system::error_code&) ()
#10 0x00000000004acdc6 in boost::asio::detail::posix_thread::func<(anonymous namespace)::threadpool_impl::add_thread()::{lambda()#1}>::run() ()
#11 0x00000000004ad4bf in boost_asio_detail_posix_thread_function ()
#12 0x00007fedbbec4dd5 in start_thread () from /lib64/libpthread.so.0
#13 0x00007fedbb6d5ead in clone () from /lib64/libc.so.6
What is wrong with the above code...? Has anyone encountered such a problem?

@yyzhang123
Copy link
Author

Has anyone encountered such a problem? help !!!

@garethsb
Copy link
Contributor

garethsb commented Jul 3, 2019

Same as #1144, #1147. response.extract_json().get() is blocking. Don't do that. Use a continuation instead, i.e. response.extract_json().then(...).

@yyzhang123
Copy link
Author

Same as #1144, #1147. response.extract_json().get() is blocking. Don't do that. Use a continuation instead, i.e. response.extract_json().then(...).

ok, thank you very much, It's really this reason. I had solve it by your suggestions。thanks!!!

@sahnnu
Copy link

sahnnu commented Aug 8, 2022

If i had to wait for some response and perform further steps only after the request is completed, then what to do in that case . Also many cpprest blogs demonstrate to wait on the request object.

https://mariusbancila.ro/blog/2017/11/19/revisited-full-fledged-client-server-example-with-c-rest-sdk-2-10/

Below is my code snippet and it seems to work for first few requests and then hangs and it retrieves after few minutes . I dnt have access to server side code and seems server side code is there for many years. I am just writing the client side code

pplx::task<web::http::http_response> request_task = client.request(request);
        try
        {        
            web_response = request_task.get();
            result = true;

        }
        catch (const std::exception& ex)
        {
            string_t errorMessage;
            ErrorMsg = L"Can't reach the confighub agent. " + utility::conversions::to_string_t(ex.what());
        }
        catch (...)
        {
            return result;
        }

@nickaein can you pls tell you changed the code at client side or server side.

@sahnnu
Copy link

sahnnu commented Aug 8, 2022

If i had to wait for some response and perform further steps only after the request is completed, then what to do in that case . Also many cpprest blogs demonstrate to wait on the request object.

https://mariusbancila.ro/blog/2017/11/19/revisited-full-fledged-client-server-example-with-c-rest-sdk-2-10/

Below is my code snippet and it seems to work for first few requests and then hangs and it retrieves after few minutes . I dnt have access to server side code and seems server side code is there for many years. I am just writing the client side code

pplx::task<web::http::http_response> request_task = client.request(request);
        try
        {        
            web_response = request_task.get();
            result = true;

        }
        catch (const std::exception& ex)
        {
            string_t errorMessage;
            ErrorMsg = L"Can't reach the confighub agent. " + utility::conversions::to_string_t(ex.what());
        }
        catch (...)
        {
            return result;
        }

@garethsb can you pls tell you changed the code at client side or server side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants