7a_echo.qbk 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. [/
  2. Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. Official repository: https://github.com/boostorg/beast
  6. ]
  7. [section:echo Echo __example__]
  8. This example develops an initiating function called [*echo].
  9. The operation will read up to the first newline on a stream, and
  10. then write the same line including the newline back on the stream.
  11. First we define the input parameters and results, then declare our
  12. initiation function. For our echo operation the only inputs are the
  13. stream and the completion token. The output is the error code which
  14. is usually included in all completion handler signatures.
  15. [example_core_echo_op_2]
  16. Now that we have a declaration, we will define the body of the function.
  17. We want to achieve the following goals: perform static type checking on
  18. the input parameters, set up the return value as per __N3747__, and launch
  19. the composed operation by constructing an intermediate, stateful completion
  20. handler and invoking it.
  21. The initiating function contains a few relatively simple parts. There is
  22. the customization of the return value type, static type checking, building
  23. the return value type using the helper, and creating and launching the
  24. `echo_op` composed operation object.
  25. The implementation strategy is to make the composed object meet the
  26. requirements of a completion handler by being movable, and by making it
  27. invocable so it can be used as a continuation for the asynchronous operations
  28. it launches. Rather than using `std::bind` or `boost::bind`, which destroys
  29. the type information and therefore breaks the allocation and invocation hooks,
  30. we will simply pass `std::move(*this)` as the completion handler parameter for
  31. any operations that we initiate. For the move to work correctly, care must be
  32. taken to ensure that no access to data members are made after the move takes
  33. place. Here is the complete implementation of our composed operation:
  34. [example_core_echo_op_3]
  35. There are some common mistakes that should be avoided when writing
  36. composed operations:
  37. * Type erasing the final handler. This will cause undefined behavior.
  38. * Forgetting to include a return statement after calling an
  39. initiating function.
  40. * Calling a synchronous function by accident. In general composed
  41. operations should not block for long periods of time, since this
  42. ties up a thread running on the __io_context__.
  43. * Forgetting to provide `executor_type` and `get_executor` for the
  44. composed operation. This will cause undefined behavior. For example,
  45. if someone calls the initiating function with a strand-wrapped
  46. function object, and there is more than thread running on the
  47. __io_context__, the underlying stream may be accessed in a fashion
  48. that violates safety guarantees. Beast provides class templates
  49. to take care of this boilerplate for you.
  50. * Forgetting to create an object of type __executor_work_guard__ with the
  51. type of executor returned by the stream's `get_executor` member function.
  52. * For operations which complete immediately (i.e. without calling an
  53. intermediate initiating function), forgetting to use __post__ to
  54. invoke the final handler. This breaks the following initiating
  55. function guarantee: ['Regardless of whether the asynchronous operation
  56. completes immediately or not, the handler will not be invoked from
  57. within this function. Invocation of the handler will be performed
  58. in a manner equivalent to using __post__]. The function
  59. __bind_handler__ is provided for this purpose.
  60. The listing for a complete, runnable version of this example is in
  61. [path_link example/echo-op/echo_op.cpp echo_op.cpp].
  62. [endsect]