Skip to content

add swoole coroutine lock docs #4776

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions reference/swoole/book.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
&reference.swoole.swoole.client;
&reference.swoole.swoole.connection.iterator;
&reference.swoole.swoole.coroutine;
&reference.swoole.swoole.coroutine.lock;
<!-- &reference.swoole.swoole.coroutine.client; -->
<!-- &reference.swoole.swoole.coroutine.http.client; -->
<!-- &reference.swoole.swoole.coroutine.mysql; -->
Expand Down
136 changes: 136 additions & 0 deletions reference/swoole/swoole.coroutine.lock.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->

<reference xml:id="class.swoole-coroutine-lock" role="class" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude">

<title>The Swoole\Coroutine\Lock class</title>
<titleabbrev>Swoole\Coroutine\Lock</titleabbrev>

<partintro>

<!-- {{{ Swoole\Coroutine\Lock intro -->
<section xml:id="swoole-coroutine-lock.intro">
&reftitle.intro;
<para>
Swoole 6.0.1 introduced a coroutine lock that supports inter-process and inter-thread sharing.
This lock is designed with non-blocking behavior and enables efficient coroutine synchronization
in multi-process and multi-thread environments.
</para>
<para>
When compiled with the <literal>--enable-iouring</literal> option and the Linux kernel supports
the <literal>io_uring futex</literal> feature, Swoole's coroutine lock implements synchronization
using <literal>io_uring futex</literal>. In this case, coroutines wait for lock wakeups using
an efficient queuing mechanism, significantly improving performance.
</para>
<para>
Without <literal>io_uring futex</literal>, the coroutine lock falls back to an exponential backoff
sleep mechanism, where the wait time increases by 2^n milliseconds (n being the number of failures)
after each failed attempt to acquire the lock. While this approach avoids busy waiting, it introduces
additional CPU scheduling overhead and latency.
</para>
<para>
The coroutine lock is reentrant, allowing the currently holding coroutine to safely perform
multiple lock operations.
</para>
<warning>
<para>
Do not create locks in callback functions like <literal>onReceive</literal>, as this will cause
continuous memory growth and lead to memory leaks.
</para>
</warning>
<warning>
<para>
Locking and unlocking must be performed in the same coroutine, otherwise it will break
static conditions.
</para>
</warning>
</section>
<!-- }}} -->

<section xml:id="swoole-coroutine-lock.synopsis">
&reftitle.classsynopsis;

<!-- {{{ Synopsis -->
<classsynopsis>
<ooclass><classname>Swoole\Coroutine\Lock</classname></ooclass>

<!-- {{{ Class synopsis -->
<classsynopsisinfo>
<ooclass>
<classname>Swoole\Coroutine\Lock</classname>
</ooclass>
</classsynopsisinfo>
<!-- }}} -->

<classsynopsisinfo role="comment">&Methods;</classsynopsisinfo>
<xi:include xpointer="xmlns(db=http://docbook.org/ns/docbook) xpointer(id('class.swoole-coroutine-lock')/db:refentry/db:refsect1[@role='description']/descendant::db:methodsynopsis[not(@role='procedural')])" />
</classsynopsis>
<!-- }}} -->

</section>

<section xml:id="swoole-coroutine-lock.examples">
&reftitle.examples;
<example xml:id="swoole-coroutine-lock.example.basic">
<title>Basic usage</title>
<programlisting role="php">
<![CDATA[
<?php
use Swoole\Coroutine\Lock;
use Swoole\Coroutine\WaitGroup;
use function Swoole\Coroutine\go;
use function Swoole\Coroutine\run;

$lock = new Lock();
$waitGroup = new WaitGroup();

run(function() use ($lock, $waitGroup) {
go(function() use ($lock, $waitGroup) {
$waitGroup->add();
$lock->lock();
sleep(1);
$lock->unlock();
$waitGroup->done();
});

go(function() use ($lock, $waitGroup) {
$waitGroup->add();
$lock->lock(); // Wait for the holding coroutine to unlock
sleep(1);
$lock->unlock();
$waitGroup->done();
});

echo 'Lock does not block the process';
$waitGroup->wait();
});
]]>
</programlisting>
</example>
</section>

</partintro>

&reference.swoole.swoole.coroutine.entities.lock;
</reference>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
53 changes: 53 additions & 0 deletions reference/swoole/swoole/coroutine/lock/construct.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->

<refentry xml:id="swoole-coroutine-lock.construct" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<refnamediv>
<refname>Swoole\Coroutine\Lock::__construct</refname>
<refpurpose>Construct a new coroutine lock</refpurpose>
</refnamediv>

<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<modifier>public</modifier> <type>void</type><methodname>Swoole\Coroutine\Lock::__construct</methodname>
<void />
</methodsynopsis>
<para>
Create a new coroutine lock instance.
</para>
</refsect1>

<refsect1 role="parameters">
&reftitle.parameters;
&no.function.parameters;
</refsect1>

<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
void
</para>
</refsect1>
</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
57 changes: 57 additions & 0 deletions reference/swoole/swoole/coroutine/lock/lock.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->

<refentry xml:id="swoole-coroutine-lock.lock" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<refnamediv>
<refname>Swoole\Coroutine\Lock::lock</refname>
<refpurpose>Acquire the lock, blocking if necessary</refpurpose>
</refnamediv>

<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<modifier>public</modifier> <type>bool</type><methodname>Swoole\Coroutine\Lock::lock</methodname>
<void />
</methodsynopsis>
<para>
When executing the lock operation, if the lock is already held by another coroutine,
the current coroutine will actively yield CPU control and enter a suspended state.
When the coroutine holding the lock calls unlock(), the waiting coroutine will be
awakened and try to acquire the lock again.
</para>
</refsect1>

<refsect1 role="parameters">
&reftitle.parameters;
&no.function.parameters;
</refsect1>

<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
Returns <literal>true</literal> if the lock was acquired successfully,
<literal>false</literal> otherwise.
</para>
</refsect1>
</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
57 changes: 57 additions & 0 deletions reference/swoole/swoole/coroutine/lock/trylock.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->

<refentry xml:id="swoole-coroutine-lock.trylock" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<refnamediv>
<refname>Swoole\Coroutine\Lock::trylock</refname>
<refpurpose>Attempt to acquire the lock without blocking</refpurpose>
</refnamediv>

<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<modifier>public</modifier> <type>bool</type><methodname>Swoole\Coroutine\Lock::trylock</methodname>
<void />
</methodsynopsis>
<para>
When calling the lock operation, if the lock is already held by another coroutine,
the function will immediately return false without suspending the current coroutine
or yielding CPU control. This non-blocking design allows the caller to flexibly
handle contention situations, such as retrying, giving up, or executing other logic.
</para>
</refsect1>

<refsect1 role="parameters">
&reftitle.parameters;
&no.function.parameters;
</refsect1>

<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
Returns <literal>true</literal> if the lock was acquired successfully,
<literal>false</literal> if the lock is not available.
</para>
</refsect1>
</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->
68 changes: 68 additions & 0 deletions reference/swoole/swoole/coroutine/lock/unlock.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->

<refentry xml:id="swoole-coroutine-lock.unlock" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<refnamediv>
<refname>Swoole\Coroutine\Lock::unlock</refname>
<refpurpose>Release the lock</refpurpose>
</refnamediv>

<refsect1 role="description">
&reftitle.description;
<methodsynopsis>
<modifier>public</modifier> <type>bool</type><methodname>Swoole\Coroutine\Lock::unlock</methodname>
<void />
</methodsynopsis>
</refsect1>

<refsect1 role="behavior">
<title>Unlock Behavior</title>
<orderedlist>
<listitem>
<para>
<emphasis>With io_uring futex:</emphasis> the system will precisely wake up one coroutine in the waiting queue.
</para>
</listitem>
<listitem>
<para>
<emphasis>Without io_uring futex:</emphasis> waiting coroutines need to wait for their backoff time to end
and compete to reacquire the lock.
</para>
</listitem>
</orderedlist>
</refsect1>

<refsect1 role="parameters">
&reftitle.parameters;
&no.function.parameters;
</refsect1>

<refsect1 role="returnvalues">
&reftitle.returnvalues;
<para>
Returns <literal>true</literal> if the lock was released successfully,
<literal>false</literal> otherwise.
</para>
</refsect1>
</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->