diff --git a/doc/sphinx/book/box/atomic.rst b/doc/sphinx/book/box/atomic.rst
index cadea351d5d3c7151a4d92bc08b535eeb50f6f48..bfa4bdcc235c4d9b741b4e9acae3dd7dbd47356f 100644
--- a/doc/sphinx/book/box/atomic.rst
+++ b/doc/sphinx/book/box/atomic.rst
@@ -1,3 +1,5 @@
+.. _atomic_execution:
+
 -------------------------------------------------------------------------------
                             Atomic execution
 -------------------------------------------------------------------------------
@@ -6,38 +8,51 @@ In several places in this manual it's been noted that Lua processes occur in fib
 single thread. That is why there can be a guarantee of execution atomicity.
 That requires emphasis.
 
+
+.. _cooperative_multitasking:
+
 ===========================================================
             Cooperative multitasking environment
 ===========================================================
 
-Tarantool uses cooperative multi-tasking: unless a
-running fiber deliberately yields control to some other fiber, it is not
-preempted. “Yield points” are built into all calls from Tarantool core to the
-operating system. Any system call which can block is performed in an
-asynchronous manner and the fiber waiting on the system call is preempted with
-a fiber ready to run. This model makes all programmatic locks unnecessary:
+Tarantool uses cooperative multitasking: unless a
+running fiber deliberately yields control, it is not
+preempted by some other fiber. 
+But a running fiber will deliberately yield when it encounters a
+"yield point": an explicit yield() request, or an implicit
+yield due to an operating-system call.
+Any system call which can block will be performed asynchronously,
+and any running fiber which must wait for a system call will be
+preempted so that another ready-to-run fiber takes its place and
+becomes the new running fiber.
+This model makes all programmatic locks unnecessary:
 cooperative multitasking ensures that there will be no concurrency around a resource,
-no race conditions and no memory consistency issues.
+no race conditions, and no memory consistency issues.
 
-When requests are small, e.g. simple UPDATE, INSERT, DELETE, SELECT, fiber
+When requests are small, for example simple UPDATE or INSERT or DELETE or SELECT, fiber
 scheduling is fair: it takes only a little time to process the request, schedule
 a disk write, and yield to a fiber serving the next client.
 
-A function, however, can perform complex computations, or be written in such a
-way that control is not given away for a long time. This can lead to unfair
+However, a function might perform complex computations or might be written in such a
+way that yields do not occur for a long time. This can lead to unfair
 scheduling, when a single client throttles the rest of the system, or to
 apparent stalls in request processing. Avoiding this situation is the
-responsibility of the function's author. Most of the box calls, such as
-:func:`box.space...insert <space_object.insert>`,
-:func:`box.space...update <space_object.update>`,
-:func:`box.space...delete <space_object.delete>` are yield points;
+responsibility of the function's author. For the default memtx storage engine
+most of the box calls, including the data-change requests
+:func:`box.space...insert <space_object.insert>` or
+:func:`box.space...update <space_object.update>` or
+:func:`box.space...delete <space_object.delete>`, are yield points;
 however, :func:`box.space...select <space_object.select>` is not.
 
-It should also be noted that, in the absence of transactions, any yield in a
-function is a potential change in the database state. Effectively, it's only
-possible to have CAS (compare-and-swap) -like atomic stored procedures: i.e.
-functions which select and then modify a record. Multiple data change requests
-always run through a built-in yield point.
+Note re storage engine: sophia has different rules:
+insert or update or delete will very rarely cause a yield,
+but select can cause a yield.
+
+In the absence of transactions, any function that contains yield points
+may see changes in the database state caused by fibers that preempt.
+Then the only safe atomic functions for memtx databases would be
+functions which contain only one database request, or functions which
+contain a select request followed by a data-change request.
 
 At this point an objection could arise: "It's good that a single data-change
 request will commit and yield, but surely there are times when multiple
@@ -49,19 +64,19 @@ block was designed.
 
 .. function:: box.begin()
 
-    From this point, implicit yields are suspended. In effect the fiber which
-    executes ``box.begin()`` is starting an "active multi-request transaction",
-    blocking all other fibers until the transaction ends. All operations within
-    this transaction should use the same storage engine.
+    Begin the transaction. Disable implicit yields until the transaction ends.
+    Signal that writes to the write-ahead log will be deferred until the transaction ends.
+    In effect the fiber which executes ``box.begin()`` is starting an "active
+    multi-request transaction", blocking all other fibers.
 
 .. function:: box.commit()
 
-    End the currently active transaction, and make all its data-change
+    End the transaction, and make all its data-change
     operations permanent.
 
 .. function:: box.rollback()
 
-    End the currently active transaction, but cancel all its data-change
+    End the transaction, but cancel all its data-change
     operations. An explicit call to functions outside ``box.space`` that always
     yield, such as ``fiber.yield`` or ``fiber.sleep``, will have the same effect.
 
@@ -70,6 +85,11 @@ It is not enough to enclose them between ``begin`` and ``commit`` or ``rollback`
 To ensure they are sent as a single block: put them in a function, or put them all
 on one line, or use a delimiter so that multi-line requests are handled together.
 
+**All database operations in a transaction should use the same storage engine**.
+It is not safe to access tuple sets that are defined with {engine='sophia'}
+and also access tuple sets that are defined with {engine='memtx'},
+in the same transaction.
+
 ===========================================================
                          Example
 ===========================================================
diff --git a/doc/sphinx/book/box/index.rst b/doc/sphinx/book/box/index.rst
index f8f9bc05d4817b1445439e89227c7f4471262799..020c3a52f845b512ace7bb07c2c83f1e10dd21a6 100644
--- a/doc/sphinx/book/box/index.rst
+++ b/doc/sphinx/book/box/index.rst
@@ -325,6 +325,8 @@ because after the UPDATE the transaction processor thread can switch
 to another fiber, and delete the tuple that was just updated.
 Note re storage engine: sophia handles yields differently, see
 :ref:`differences between memtx and sophia <sophia_diff>`.
+Note re multi-request transactions: there is a way to delay yields,
+see :ref:`Atomic execution <atomic_execution>`.
 
 Since locks don't exist, and disk writes only involve the write-ahead log,
 transactions are usually fast. Also the Tarantool server may not be using
diff --git a/doc/sphinx/book/box/sophia_diff.rst b/doc/sphinx/book/box/sophia_diff.rst
index 9bac36dd7f44230e8d542aee15c5dbd48fc0e4cb..924ef45d3b52a51d3d57c3a7a955d90f98b1cd8a 100644
--- a/doc/sphinx/book/box/sophia_diff.rst
+++ b/doc/sphinx/book/box/sophia_diff.rst
@@ -55,7 +55,7 @@
     It was explained :ref:`earlier <yields_must_happen>` that memtx does not "yield" on a select request,
     it yields only on data-change requests. However, sophia does yield on a select
     request, or on an equivalent such as get() or pairs(). This has significance
-    for cooperative multitasking. 
+    for :ref:`cooperative multitasking <cooperative_multitasking>`. 
 
     For more about sophia, see Appendix E :ref:`sophia <sophia>`.