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

specific async pattern implementation query #930

Open
borisu opened this issue Apr 13, 2024 · 4 comments
Open

specific async pattern implementation query #930

borisu opened this issue Apr 13, 2024 · 4 comments
Labels
Question Further information is requested

Comments

@borisu
Copy link

borisu commented Apr 13, 2024

In order to integrate oatpp into the project I need to follow rigid asynchronous threading model. Specifically speaking, on http request callback I cannot return the result immediately, I need to transfer control to other module (running in different thread, or even different network service) and then it will supply me back the result.
I can implement it with sync API by blocking the response till mentioned module finishes the job but it will consume the thread for the time the request being processed, which I guess make handling many parallel requests inefficient. So I need to release the control immediately and then somehow inform the oatpp that the response is ready and it needs to be sent to the channel the http request was received from. But looking into oatpp API i just can't get a clue how to write such thing. I looked into coroutines and IO_READ/WRITE actions tasks but couldn't get my head around the details. Any help will be much appreciated.

The framework in general has the following form

oatpp::HttpRequestHandler::handleAsync(request)
{
enqueu_3rdparty_request() // send the async request to the unknown module
return ??? // <-- return action which just waits for the response
}

Unknown3rdPartyModule::onRequest()
{
// do some very long work
// do something that wakes up the oapp action in "waiting list" and continues with the supplied resonse
{

@lganzzzo
Copy link
Member

Hello @borisu ,

You can do it with oatpp::async::ConditionVariable and oatpp::async::Lock

Here is example:

Declare Lock and CV to share between oatpp coroutine and some other thread:

oatpp::async::Lock lock;
oatpp::async::ConditionVariable cv;

Coroutine:

class TestCoroutineWait : public oatpp::async::Coroutine<TestCoroutineWait> {
private:
  std::shared_ptr<Resource> m_resource;
  oatpp::async::LockGuard m_lockGuard; // Use async::LockGuard to guard the lock
  oatpp::async::ConditionVariable* m_cv;
public:

  TestCoroutineWait(std::shared_ptr<Resource> resource,
                    oatpp::async::Lock* lock,              // pass async::Lock to coroutine
                    oatpp::async::ConditionVariable* cv)   // pass async::ConditionVariable to coroutine
    : m_resource(resource)
    , m_lockGuard(lock)
    , m_cv(cv)
  {}

  Action act() override {
    return m_cv->wait(m_lockGuard, [this]{return m_resource->counter == 100;}) // long wait until counter == 100
            .next(yieldTo(&TestCoroutineWait::onReady));
  }

  Action onReady() {
    OATPP_ASSERT(m_lockGuard.owns_lock()) // Now coroutine owns the lock
    return finish();
  }

};

Other thread:

std::thread t([&resource, &lock, &cv] {
  { // very long operation
    std::lock_guard<oatpp::async::Lock> guard(lock);
    for(int i = 0; i < 100; i++) {
      resource->counter++;
    }
  }
  cv.notifyAll();
})

Note1: you can find working example here - https://github.com/oatpp/oatpp/blob/master/test/oatpp/core/async/ConditionVariableTest.cpp

Note2: It's possible to implement it with just oatpp::async::CoroutineWaitList but it's cleaner to use do it this way. There are details that you may miss when working with CoroutineWaitList.

Note3: Always use thread pool in case you are spawning threads from coroutine.

Note4: Make sure to have latest master as oatpp::async::ConditionVariable is an early feature of 1.4.0 available already in 1.3.0

@lganzzzo lganzzzo added the Question Further information is requested label Apr 16, 2024
@borisu
Copy link
Author

borisu commented Apr 17, 2024

Thanks a lot , I will try it and ccomment here with results

@borisu
Copy link
Author

borisu commented Apr 27, 2024

Worked well. Thanks Indeed I needed to upgrade to 1.3-latest as I understand it was relatively new additions.

@borisu
Copy link
Author

borisu commented May 11, 2024

@lganzzzo I am using vcpkg for the project and it seams like oatpp::async::ConditionVariable is still not vailable there, when are you (if at all) planning to update vcpkg with new 1.4.0 package?

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

No branches or pull requests

2 participants