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

Does it have a coro lock? #935

Open
nqf opened this issue Nov 12, 2021 · 4 comments
Open

Does it have a coro lock? #935

nqf opened this issue Nov 12, 2021 · 4 comments

Comments

@nqf
Copy link

nqf commented Nov 12, 2021

asio::mutex mutex;
	asio::co_spawn(
		pool, [&]() -> asio::awaitable<void> {
                        // Does ASIO have such a lock?
			co_await mutex.lock();
		},
		asio::detached);
@Maximsiv1410
Copy link

Maximsiv1410 commented Nov 19, 2021

I join the question, are you @chriskohlhoff planning to add something like async_mutex from cppcoro? It's not about thread synchronization, but about prevention of concurrent execution of coroutines at some code points.. I believe there is no way to achieve such behavior with strands. Also there is similar async_mutex in libunifex of facebook.
Would be very useful! :)
Correct me if i'm wrong.

@nqf
Copy link
Author

nqf commented Dec 3, 2021

cppcoro::task<std::string> query_redis(const std::string& key) {
	std::cout << "query redis:" << key << std::endl;
	co_return std::string{"hello"};
}

asio::awaitable<void> echo(asio::ip::tcp::socket socket) {
	char data[1024];
	for (;;) {
		std::size_t n = co_await socket.async_read_some(asio::buffer(data), asio::use_awaitable);
		auto key = co_await query_redis(std::string{data});
		std::cout << "key:" << key << std::endl;
		auto w = co_await socket.async_write_some(asio::buffer(data, n), asio::use_awaitable);
	}
}


[ 50%] Building CXX object CMakeFiles/corod.dir/src/main.cpp.o
/home/xxxxx/coro/src/main.cpp: In function ‘asio::awaitable<void> echo(asio::ip::tcp::socket)’:
/home/xxxxx/coro/src/main.cpp:80:53: error: no matching function for call to ‘asio::detail::awaitable_frame<void, asio::any_io_executor>::await_transform(cppcoro::task<std::basic_string<char> >)’
   80 |    auto key = co_await query_redis(std::string{data});
      |                                                     ^
In file included from /home/xxxxx/coro/deps/.src/asio/asio/include/asio/awaitable.hpp:129,
                 from /home/xxxxx/coro/deps/.src/asio/asio/include/asio.hpp:23,
                 from /home/xxxxx/coro/src/main.cpp:15:
/home/xxxxx/coro/deps/.src/asio/asio/include/asio/impl/awaitable.hpp:161:8: note: candidate: ‘template<class T> auto asio::detail::awaitable_frame_base<Executor>::await_transform(asio::awaitable<T, Executor>) const [with T = T; Executor = asio::any_io_executor]’
  161 |   auto await_transform(awaitable<T, Executor> a) const
      |        ^~~~~~~~~~~~~~~
/home/xxxxx/coro/deps/.src/asio/asio/include/asio/impl/awaitable.hpp:161:8: note:   template argument deduction/substitution failed:
/home/xxxxx/coro/src/main.cpp:80:53: note:   ‘cppcoro::task<std::basic_string<char> >’ is not derived from ‘asio::awaitable<T, asio::any_io_executor>’
   80 |    auto key = co_await query_redis(std::string{data});
      |                                                     ^
In file included from /home/xxxxx/coro/deps/.src/asio/asio/include/asio/awaitable.hpp:129,
                 from /home/xxxxx/coro/deps/.src/asio/asio/include/asio.hpp:23,
                 from /home/xxxxx/coro/src/main.cpp:15:
/home/xxxxx/coro/deps/.src/asio/asio/include/asio/impl/awaitable.hpp:171:8: note: candidate: ‘auto asio::detail::awaitable_frame_base<Executor>::await_transform(asio::this_coro::executor_t) [with Executor = asio::any_io_executor]’
  171 |   auto await_transform(this_coro::executor_t) noexcept
      |        ^~~~~~~~~~~~~~~
/home/xxxxx/coro/deps/.src/asio/asio/include/asio/impl/awaitable.hpp:171:24: note:   no known conversion for argument 1 from ‘cppcoro::task<std::basic_string<char> >’ to ‘asio::this_coro::executor_t’
  171 |   auto await_transform(this_coro::executor_t) noexcept
      |                        ^~~~~~~~~~~~~~~~~~~~~
/home/xxxxx/coro/deps/.src/asio/asio/include/asio/impl/awaitable.hpp:197:8: note: candidate: ‘auto asio::detail::awaitable_frame_base<Executor>::await_transform(asio::this_coro::cancellation_state_t) [with Executor = asio::any_io_executor]’
  197 |   auto await_transform(this_coro::cancellation_state_t) noexcept
      |        ^~~~~~~~~~~~~~~
/home/xxxxx/coro/deps/.src/asio/asio/include/asio/impl/awaitable.hpp:197:24: note:   no known conversion for argument 1 from ‘cppcoro::task<std::basic_string<char> >’ to ‘asio::this_coro::cancellation_state_t’
  197 |   auto await_transform(this_coro::cancellation_state_t) noexcept

It doesn't seem to work with other libraries, I don't know how to deal with this situation

@microcai
Copy link
Contributor

microcai commented Feb 7, 2022

no such thing, at present ;)
but you can always re-invent your own wheel.

@yuraaka
Copy link

yuraaka commented Nov 29, 2023

I reinvented it this way (maybe will be useful for someone):

class coro_strand {
  public:
      coro_strand(boost::asio::io_service& ios)
          : ios_(ios)
      {
      }

      template <typename Coroutine>
      boost::asio::awaitable<void> async_post(Coroutine&& coro) {
          co_await boost::asio::co_spawn(ios_, [&] mutable -> boost::asio::awaitable<void> {
              ++pending_;
              auto finally = make_on_exit_scope([&]() {
                  if (--pending_) {
                      schedule_next();
                  }
              });

              if (pending_ == 1) {
                  co_await coro();
              } else {
                  co_await async_defer(coro);
              }
          }, boost::asio::use_awaitable);
      }

  private:
      void schedule_next() {
          boost::asio::post(ios_, [&]() { queue_.run_one(); });
      }

      template <typename Coroutine>
      boost::asio::awaitable<void> async_defer(Coroutine&& coro) {
          if (queue_.stopped()) {
              queue_.restart();
          }

          co_await boost::asio::co_spawn(queue_, [&] mutable -> boost::asio::awaitable<void> {
              co_await boost::asio::co_spawn(ios_, [&] mutable -> boost::asio::awaitable<void> {
                  auto finally = make_on_exit_scope([&]() { schedule_next(); });
                  co_await coro();
              }, boost::asio::use_awaitable);
          }, boost::asio::use_awaitable);
      }

  private:
      boost::asio::io_service& ios_;
      boost::asio::io_service queue_;
      size_t pending_ = 0;
  };

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

4 participants