Skip to content

Commit 785e575

Browse files
committed
add swoole coroutine lock
1 parent 09324fb commit 785e575

File tree

6 files changed

+372
-0
lines changed

6 files changed

+372
-0
lines changed

reference/swoole/book.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
&reference.swoole.swoole.client;
3535
&reference.swoole.swoole.connection.iterator;
3636
&reference.swoole.swoole.coroutine;
37+
&reference.swoole.swoole.coroutine.lock;
3738
<!-- &reference.swoole.swoole.coroutine.client; -->
3839
<!-- &reference.swoole.swoole.coroutine.http.client; -->
3940
<!-- &reference.swoole.swoole.coroutine.mysql; -->
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- $Revision$ -->
3+
4+
<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">
5+
6+
<title>The Swoole\Coroutine\Lock class</title>
7+
<titleabbrev>Swoole\Coroutine\Lock</titleabbrev>
8+
9+
<partintro>
10+
11+
<!-- {{{ Swoole\Coroutine\Lock intro -->
12+
<section xml:id="swoole-coroutine-lock.intro">
13+
&reftitle.intro;
14+
<para>
15+
Swoole 6.0.1 introduced a coroutine lock that supports inter-process and inter-thread sharing.
16+
This lock is designed with non-blocking behavior and enables efficient coroutine synchronization
17+
in multi-process and multi-thread environments.
18+
</para>
19+
<para>
20+
When compiled with the <literal>--enable-iouring</literal> option and the Linux kernel supports
21+
the <literal>io_uring futex</literal> feature, Swoole's coroutine lock implements synchronization
22+
using <literal>io_uring futex</literal>. In this case, coroutines wait for lock wakeups using
23+
an efficient queuing mechanism, significantly improving performance.
24+
</para>
25+
<para>
26+
Without <literal>io_uring futex</literal>, the coroutine lock falls back to an exponential backoff
27+
sleep mechanism, where the wait time increases by 2^n milliseconds (n being the number of failures)
28+
after each failed attempt to acquire the lock. While this approach avoids busy waiting, it introduces
29+
additional CPU scheduling overhead and latency.
30+
</para>
31+
<para>
32+
The coroutine lock is reentrant, allowing the currently holding coroutine to safely perform
33+
multiple lock operations.
34+
</para>
35+
<warning>
36+
<para>
37+
Do not create locks in callback functions like <literal>onReceive</literal>, as this will cause
38+
continuous memory growth and lead to memory leaks.
39+
</para>
40+
</warning>
41+
<warning>
42+
<para>
43+
Locking and unlocking must be performed in the same coroutine, otherwise it will break
44+
static conditions.
45+
</para>
46+
</warning>
47+
</section>
48+
<!-- }}} -->
49+
50+
<section xml:id="swoole-coroutine-lock.synopsis">
51+
&reftitle.classsynopsis;
52+
53+
<!-- {{{ Synopsis -->
54+
<classsynopsis>
55+
<ooclass><classname>Swoole\Coroutine\Lock</classname></ooclass>
56+
57+
<!-- {{{ Class synopsis -->
58+
<classsynopsisinfo>
59+
<ooclass>
60+
<classname>Swoole\Coroutine\Lock</classname>
61+
</ooclass>
62+
</classsynopsisinfo>
63+
<!-- }}} -->
64+
65+
<classsynopsisinfo role="comment">&Methods;</classsynopsisinfo>
66+
<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')])" />
67+
</classsynopsis>
68+
<!-- }}} -->
69+
70+
</section>
71+
72+
<section xml:id="swoole-coroutine-lock.examples">
73+
&reftitle.examples;
74+
<example xml:id="swoole-coroutine-lock.example.basic">
75+
<title>Basic usage</title>
76+
<programlisting role="php">
77+
<![CDATA[
78+
<?php
79+
use Swoole\Coroutine\Lock;
80+
use Swoole\Coroutine\WaitGroup;
81+
use function Swoole\Coroutine\go;
82+
use function Swoole\Coroutine\run;
83+
84+
$lock = new Lock();
85+
$waitGroup = new WaitGroup();
86+
87+
run(function() use ($lock, $waitGroup) {
88+
go(function() use ($lock, $waitGroup) {
89+
$waitGroup->add();
90+
$lock->lock();
91+
sleep(1);
92+
$lock->unlock();
93+
$waitGroup->done();
94+
});
95+
96+
go(function() use ($lock, $waitGroup) {
97+
$waitGroup->add();
98+
$lock->lock(); // Wait for the holding coroutine to unlock
99+
sleep(1);
100+
$lock->unlock();
101+
$waitGroup->done();
102+
});
103+
104+
echo 'Lock does not block the process';
105+
$waitGroup->wait();
106+
});
107+
]]>
108+
</programlisting>
109+
</example>
110+
</section>
111+
112+
</partintro>
113+
114+
&reference.swoole.swoole.coroutine.entities.lock;
115+
</reference>
116+
117+
<!-- Keep this comment at the end of the file
118+
Local variables:
119+
mode: sgml
120+
sgml-omittag:t
121+
sgml-shorttag:t
122+
sgml-minimize-attributes:nil
123+
sgml-always-quote-attributes:t
124+
sgml-indent-step:1
125+
sgml-indent-data:t
126+
indent-tabs-mode:nil
127+
sgml-parent-document:nil
128+
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
129+
sgml-exposed-tags:nil
130+
sgml-local-catalogs:nil
131+
sgml-local-ecat-files:nil
132+
End:
133+
vim600: syn=xml fen fdm=syntax fdl=2 si
134+
vim: et tw=78 syn=sgml
135+
vi: ts=1 sw=1
136+
-->
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- $Revision$ -->
3+
4+
<refentry xml:id="swoole-coroutine-lock.construct" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
5+
<refnamediv>
6+
<refname>Swoole\Coroutine\Lock::__construct</refname>
7+
<refpurpose>Construct a new coroutine lock</refpurpose>
8+
</refnamediv>
9+
10+
<refsect1 role="description">
11+
&reftitle.description;
12+
<methodsynopsis>
13+
<modifier>public</modifier> <type>void</type><methodname>Swoole\Coroutine\Lock::__construct</methodname>
14+
<void />
15+
</methodsynopsis>
16+
<para>
17+
Create a new coroutine lock instance.
18+
</para>
19+
</refsect1>
20+
21+
<refsect1 role="parameters">
22+
&reftitle.parameters;
23+
&no.function.parameters;
24+
</refsect1>
25+
26+
<refsect1 role="returnvalues">
27+
&reftitle.returnvalues;
28+
<para>
29+
void
30+
</para>
31+
</refsect1>
32+
</refentry>
33+
34+
<!-- Keep this comment at the end of the file
35+
Local variables:
36+
mode: sgml
37+
sgml-omittag:t
38+
sgml-shorttag:t
39+
sgml-minimize-attributes:nil
40+
sgml-always-quote-attributes:t
41+
sgml-indent-step:1
42+
sgml-indent-data:t
43+
indent-tabs-mode:nil
44+
sgml-parent-document:nil
45+
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
46+
sgml-exposed-tags:nil
47+
sgml-local-catalogs:nil
48+
sgml-local-ecat-files:nil
49+
End:
50+
vim600: syn=xml fen fdm=syntax fdl=2 si
51+
vim: et tw=78 syn=sgml
52+
vi: ts=1 sw=1
53+
-->
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- $Revision$ -->
3+
4+
<refentry xml:id="swoole-coroutine-lock.lock" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
5+
<refnamediv>
6+
<refname>Swoole\Coroutine\Lock::lock</refname>
7+
<refpurpose>Acquire the lock, blocking if necessary</refpurpose>
8+
</refnamediv>
9+
10+
<refsect1 role="description">
11+
&reftitle.description;
12+
<methodsynopsis>
13+
<modifier>public</modifier> <type>bool</type><methodname>Swoole\Coroutine\Lock::lock</methodname>
14+
<void />
15+
</methodsynopsis>
16+
<para>
17+
When executing the lock operation, if the lock is already held by another coroutine,
18+
the current coroutine will actively yield CPU control and enter a suspended state.
19+
When the coroutine holding the lock calls unlock(), the waiting coroutine will be
20+
awakened and try to acquire the lock again.
21+
</para>
22+
</refsect1>
23+
24+
<refsect1 role="parameters">
25+
&reftitle.parameters;
26+
&no.function.parameters;
27+
</refsect1>
28+
29+
<refsect1 role="returnvalues">
30+
&reftitle.returnvalues;
31+
<para>
32+
Returns <literal>true</literal> if the lock was acquired successfully,
33+
<literal>false</literal> otherwise.
34+
</para>
35+
</refsect1>
36+
</refentry>
37+
38+
<!-- Keep this comment at the end of the file
39+
Local variables:
40+
mode: sgml
41+
sgml-omittag:t
42+
sgml-shorttag:t
43+
sgml-minimize-attributes:nil
44+
sgml-always-quote-attributes:t
45+
sgml-indent-step:1
46+
sgml-indent-data:t
47+
indent-tabs-mode:nil
48+
sgml-parent-document:nil
49+
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
50+
sgml-exposed-tags:nil
51+
sgml-local-catalogs:nil
52+
sgml-local-ecat-files:nil
53+
End:
54+
vim600: syn=xml fen fdm=syntax fdl=2 si
55+
vim: et tw=78 syn=sgml
56+
vi: ts=1 sw=1
57+
-->
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- $Revision$ -->
3+
4+
<refentry xml:id="swoole-coroutine-lock.trylock" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
5+
<refnamediv>
6+
<refname>Swoole\Coroutine\Lock::trylock</refname>
7+
<refpurpose>Attempt to acquire the lock without blocking</refpurpose>
8+
</refnamediv>
9+
10+
<refsect1 role="description">
11+
&reftitle.description;
12+
<methodsynopsis>
13+
<modifier>public</modifier> <type>bool</type><methodname>Swoole\Coroutine\Lock::trylock</methodname>
14+
<void />
15+
</methodsynopsis>
16+
<para>
17+
When calling the lock operation, if the lock is already held by another coroutine,
18+
the function will immediately return false without suspending the current coroutine
19+
or yielding CPU control. This non-blocking design allows the caller to flexibly
20+
handle contention situations, such as retrying, giving up, or executing other logic.
21+
</para>
22+
</refsect1>
23+
24+
<refsect1 role="parameters">
25+
&reftitle.parameters;
26+
&no.function.parameters;
27+
</refsect1>
28+
29+
<refsect1 role="returnvalues">
30+
&reftitle.returnvalues;
31+
<para>
32+
Returns <literal>true</literal> if the lock was acquired successfully,
33+
<literal>false</literal> if the lock is not available.
34+
</para>
35+
</refsect1>
36+
</refentry>
37+
38+
<!-- Keep this comment at the end of the file
39+
Local variables:
40+
mode: sgml
41+
sgml-omittag:t
42+
sgml-shorttag:t
43+
sgml-minimize-attributes:nil
44+
sgml-always-quote-attributes:t
45+
sgml-indent-step:1
46+
sgml-indent-data:t
47+
indent-tabs-mode:nil
48+
sgml-parent-document:nil
49+
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
50+
sgml-exposed-tags:nil
51+
sgml-local-catalogs:nil
52+
sgml-local-ecat-files:nil
53+
End:
54+
vim600: syn=xml fen fdm=syntax fdl=2 si
55+
vim: et tw=78 syn=sgml
56+
vi: ts=1 sw=1
57+
-->
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- $Revision$ -->
3+
4+
<refentry xml:id="swoole-coroutine-lock.unlock" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
5+
<refnamediv>
6+
<refname>Swoole\Coroutine\Lock::unlock</refname>
7+
<refpurpose>Release the lock</refpurpose>
8+
</refnamediv>
9+
10+
<refsect1 role="description">
11+
&reftitle.description;
12+
<methodsynopsis>
13+
<modifier>public</modifier> <type>bool</type><methodname>Swoole\Coroutine\Lock::unlock</methodname>
14+
<void />
15+
</methodsynopsis>
16+
</refsect1>
17+
18+
<refsect1 role="behavior">
19+
<title>Unlock Behavior</title>
20+
<orderedlist>
21+
<listitem>
22+
<para>
23+
<emphasis>With io_uring futex:</emphasis> the system will precisely wake up one coroutine in the waiting queue.
24+
</para>
25+
</listitem>
26+
<listitem>
27+
<para>
28+
<emphasis>Without io_uring futex:</emphasis> waiting coroutines need to wait for their backoff time to end
29+
and compete to reacquire the lock.
30+
</para>
31+
</listitem>
32+
</orderedlist>
33+
</refsect1>
34+
35+
<refsect1 role="parameters">
36+
&reftitle.parameters;
37+
&no.function.parameters;
38+
</refsect1>
39+
40+
<refsect1 role="returnvalues">
41+
&reftitle.returnvalues;
42+
<para>
43+
Returns <literal>true</literal> if the lock was released successfully,
44+
<literal>false</literal> otherwise.
45+
</para>
46+
</refsect1>
47+
</refentry>
48+
49+
<!-- Keep this comment at the end of the file
50+
Local variables:
51+
mode: sgml
52+
sgml-omittag:t
53+
sgml-shorttag:t
54+
sgml-minimize-attributes:nil
55+
sgml-always-quote-attributes:t
56+
sgml-indent-step:1
57+
sgml-indent-data:t
58+
indent-tabs-mode:nil
59+
sgml-parent-document:nil
60+
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
61+
sgml-exposed-tags:nil
62+
sgml-local-catalogs:nil
63+
sgml-local-ecat-files:nil
64+
End:
65+
vim600: syn=xml fen fdm=syntax fdl=2 si
66+
vim: et tw=78 syn=sgml
67+
vi: ts=1 sw=1
68+
-->

0 commit comments

Comments
 (0)