Closed remorhaz closed 5 years ago
Can you try with the latest versions of each of the libraries and let me know if you're still having this problem? Thanks!
I've tried to reproduce the problem today. I have upgraded to krakjoe/pthreads:3.2.1dev
, amphp/parallel:1.1.1
and amphp/websocket:0.2.3
. I had to add yield
before Thread::run()
call because it returns promise now. But then I experienced some problems.
At first, handshake used League\Uri\WS
class that was not available, so I had to add leadue/uri-schemes:1.2.1
manually. Probably you have missed some internal dependencies, please check it.
Then I've stumbled upon the Did not receive switching protocols response: HTTP/1.0 400 Bad Request: invalid request line
error and am trying to solve it now (maybe my server behaves wrong or I need more modifications to old code), but at this point (WS connection established) my script hangs in the same manner it used to do before. So my provisional answer is yes, the problem remains in modernized environment. I will try to make my code work as it worked before and then I will provide you with the updated way to reproduce.
Whoops, yes, league/uri-schemes
was suppose to be required instead of uri-parser
. I missed that because under dev we have amphp/http-server
, which installs uri-schemes
. I tagged 0.2.4
that fixes this.
The invalid request line
error concerns me. Can I ask what URI you're connecting to? Or at least an example of what it looks like?
I've refactored master to use a new shared repo amphp/websocket
. Could you try with dev-master
as well? You code will require some namespace changes (from Amp\Websocket
to Amp\Websocket\Client
), and perhaps a couple of minor changes as options are now passed to the Handshake
object.
I've investigated the invalid request line
case. The bug is in lib/Handshake.php:70
:
$path = $this->uri->getPath() ?? '/';
getPath()
always returns string
, so when it returns empty string, it is not replaced with slash (resulting in broken request). I used URI ws://local.websocket:8080
in my example, adding /
to it solves the problem, but you definitely should fix that.
I will repeat experiment with dev-master
and report you a bit later.
Ah, guess that's my fault for always having a /
in tests and confusing with PSR-7 UriInterface
that returns null
. I'll let you experiment more before tagging another version.
Now my code runs okay, but establishing a WS connection still hangs the script in the end, so the problem still exists in upgraded environment. I will post here the the updated code for your convenience:
<?php
require_once __DIR__ . '/../vendor/autoload.php';
ob_start();
phpinfo(INFO_MODULES);
$phpinfo = ob_get_clean();
if (1 !== preg_match('#^pthreads(?:.+?)^Version\s+=>\s+(.*?)$#sm', $phpinfo, $matches)) {
die("Failed to detect pthreads version");
}
echo "Pthreads version: {$matches[1]}\n";
$delay = 2;
echo "Program started\n";
sleep($delay);
\Amp\Loop::run(
function () use ($delay) {
echo "Loop started\n";
sleep($delay);
/** @var \Amp\Parallel\Context\Thread $thread */
$thread = yield \Amp\Parallel\Context\Thread::run(
function (\Amp\Parallel\Sync\Channel $channel, int $delay) {
echo "Thread started\n";
$ticker = \Amp\Loop::repeat(
1000,
function () {
static $counter = 0;
echo "Tick from thread: ", $counter++, "\n";
}
);
sleep($delay);
echo "Thread loop started\n";
\Amp\Loop::run(
function () use ($channel, $ticker) {
/** @var Amp\Websocket\Client\Connection $connection */
$connection = yield \Amp\Websocket\Client\connect("ws://local.websocket:8080/");
$data = yield $channel->receive();
if ('stop' == $data) {
\Amp\Loop::cancel($ticker);
echo "Ticker stopped\n";
echo "Connection is open: ", $connection->isConnected() ? 'YES' : 'NO', "\n";
$connection->close();
echo "Connection is open: ", $connection->isConnected() ? 'YES' : 'NO', "\n";
}
}
);
echo "Out of thread loop\n";
},
$delay
);
sleep($delay * 2);
yield $thread->send('stop');
yield $thread->join();
echo "Thread joined\n";
}
);
echo "Out of loop\n";
It outputs (and then hangs):
Pthreads version: 3.2.1dev
Program started
Loop started
Thread started
Thread loop started
Tick from thread: 0
Tick from thread: 1
Ticker stopped
Connection is open: YES
Connection is open: NO
Out of thread loop
Thread joined
Out of loop
My composer.json
is:
{
"minimum-stability": "dev",
"require": {
"php": "^7.2",
"amphp/parallel": "1.1.1",
"amphp/websocket-client": "dev-master"
}
}
composer show
reports the following library versions:
amphp/amp v2.1.1 A non-blocking concurrency framework for PHP applications.
amphp/byte-stream v1.5.1 A stream abstraction to make working with non-blocking I/O simple.
amphp/cache v1.2.0 A promise-aware caching API for Amp.
amphp/dns v0.9.13 Async DNS resolution for Amp.
amphp/file v0.3.3 Allows non-blocking access to the filesystem for Amp.
amphp/http v1.0.1 Basic HTTP primitives which can be shared by servers and clients.
amphp/parallel v1.1.1 Parallel processing component for Amp.
amphp/parser v1.0.0 A generator parser to make streaming parsers simple.
amphp/process v1.0.3 Asynchronous process manager.
amphp/socket v0.10.11 Async socket connection / server tools for Amp.
amphp/sync v1.0.1 Mutex, Semaphore, and other synchronization tools for Amp.
amphp/uri v0.1.3 Uri Parser and Resolver.
amphp/websocket dev-master b7f48ad Shared code for websocket servers and clients.
amphp/websocket-client dev-master 9ebf93e Async WebSocket client for PHP based on Amp.
amphp/windows-registry v0.3.2 Windows Registry Reader.
daverandom/libdns 2.x-dev 1ecd825 DNS protocol implementation written in pure PHP
league/uri-interfaces dev-master 081760c Common interface for URI representation
league/uri-parser dev-master 6715484 userland URI parser RFC 3986 compliant
league/uri-schemes dev-master f821a44 URI manipulation library
psr/http-message dev-master f6561bf Common interface for HTTP messages
@remorhaz Based on your program's output, I'm guessing the problem is actually not in this library, but either in amphp/parallel
or in pthreads
.
Could you add an echo "Out of Internal Thread Loop\n"
after this line within the Thread
instance that is being run. The call to Loop::run()
in your example should be exiting the same loop, so it shouldn't matter, but I'm curious.
Also note that you do not need to call Loop::run()
within the callback given to Thread::run()
. The callback will be run as a coroutine within a running event loop. That should not be a problem, but you could try removing that too.
After adding the line you've asked the script outputs the following (and still hangs):
Pthreads version: 3.2.1dev
Program started
Loop started
Thread started
Thread loop started
Tick from thread: 0
Tick from thread: 1
Ticker stopped
Connection is open: YES
Connection is open: NO
Out of thread loop
Out of Internal Thread Loop
Thread joined
Out of loop
Then I've inlined the code from the nested loop (and increased a delay up to 3 seconds to watch if the ticker really ticks) and got the following output (and the script still hangs):
Pthreads version: 3.2.1dev
Program started
Loop started
Thread started
Thread loop started
Tick from thread: 0
Tick from thread: 1
Tick from thread: 2
Ticker stopped
Connection is open: YES
Connection is open: NO
Out of thread loop
Thread joined
Out of loop
It's interesting that without nested callback "Out of Internal Thread Loop" is not printed. Another wierd thing is that I'm always getting one tick more with nested callback - I don't understand why. But anyway, the script hangs.
I've tried to look what's really happening with process threads when my script runs. I've set up delay to 30 and discovered the following:
root@f865272b6acc:/app# ps -T -p 1
PID SPID TTY TIME CMD
1 1 pts/0 00:00:00 php
root@f865272b6acc:/app# ps -T -p 1
PID SPID TTY TIME CMD
1 1 pts/0 00:00:00 php
1 19 pts/0 00:00:00 php
root@f865272b6acc:/app# ps -T -p 1
PID SPID TTY TIME CMD
1 1 pts/0 00:00:00 php
1 19 pts/0 00:00:00 php
1 21 pts/0 00:00:00 php
When the script ends(and hangs) the picture is the same as on 3), so joining the threads didn't really occur on join()
call.
When I comment out all the work with $connection
, the picture is the following:
1) The thread hasn't started yet:
root@8a506f92be7b:/app# ps -T -p 1
PID SPID TTY TIME CMD
1 1 pts/0 00:00:00 php
2) The thread has started, and we see it:
root@8a506f92be7b:/app# ps -T -p 1
PID SPID TTY TIME CMD
1 1 pts/0 00:00:00 php
1 18 pts/0 00:00:00 php
3) The thread has joined: the second thread disappeared.
root@8a506f92be7b:/app# ps -T -p 1
PID SPID TTY TIME CMD
1 1 pts/0 00:00:00 php
And the script doesn't hang. So we have two unanswered questions:
join()
leaves both threads alive and reports success?Looks like another thread is being started to do the file access to read the hosts file so amphp/dns
can lookup local.websocket
. If you have some time to debug, I'd be interested in knowing why this thread isn't being stopped automatically by this code. It probably has something to do with the fact that the worker is starting a thread from within another thread. You can try adding define('AMP_WORKER', 'amp-worker')
to the top of the function provided to Thread::run()
. It will force the blocking (sync) file driver to be used within the thread. If that helps, I may consider using the blocking file driver by default within thread contexts.
We recently removed the async file access in amphp/dns
for reading the host file. I just tagged v0.9.14
. Note that you can also install either ext-eio
or ext-uv
to have thread-based, async file reading with better performance than that provided by amphp/parallel
file driver.
Well, defining 'AMP_WORKER'
solves the problem, so you were right and the problem is in async file driver.
I've added a bit more debugging information (file/line applied) and got wierd results.
Experiment 1: WITH nested Loop::run()
Pthreads version: 3.2.1dev
Program started
Loop started
Internal thread constructed (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:44)
#0 Amp\Parallel\Context\Internal\Thread->__construct() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:160]
#1 Amp\Parallel\Context\Thread->start() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:70]
#2 Amp\Parallel\Context\Thread::Amp\Parallel\Context\{closure}()
#3 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#4 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#5 Amp\call() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:72]
#6 Amp\Parallel\Context\Thread::run() called at [/app/src/demo.php:56]
#7 {closure}()
#8 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#9 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:123]
#10 Amp\Loop\Driver->tick() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:72]
#11 Amp\Loop\Driver->run() called at [/app/vendor/amphp/amp/lib/Loop.php:84]
#12 Amp\Loop::run() called at [/app/src/demo.php:64]
Internal thread running: 139956973586176 (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:86)
Thread started
Okay, first thread *176
is the one constructed directly in our example.
Thread loop started
Worker constructed: Amp\Parallel\Context\Thread (/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:42)
Internal thread constructed (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:44)
#0 Amp\Parallel\Context\Internal\Thread->__construct() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:160]
#1 Amp\Parallel\Context\Thread->start() called at [/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:105]
#2 Amp\Parallel\Worker\TaskWorker->Amp\Parallel\Worker\{closure}()
#3 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#4 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#5 Amp\call() called at [/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:129]
#6 Amp\Parallel\Worker\TaskWorker->enqueue() called at [/app/vendor/amphp/parallel/lib/Worker/DefaultPool.php:152]
#7 Amp\Parallel\Worker\DefaultPool->enqueue() called at [/app/vendor/amphp/file/lib/ParallelDriver.php:50]
#8 Amp\File\ParallelDriver->runFileTask()
#9 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#10 Amp\Coroutine->__construct() called at [/app/vendor/amphp/file/lib/ParallelDriver.php:286]
#11 Amp\File\ParallelDriver->get() called at [/app/vendor/amphp/file/lib/functions.php:339]
#12 Amp\File\get() called at [/app/vendor/amphp/dns/lib/UnixConfigLoader.php:27]
#13 Amp\Dns\UnixConfigLoader->Amp\Dns\{closure}()
#14 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#15 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#16 Amp\call() called at [/app/vendor/amphp/dns/lib/UnixConfigLoader.php:78]
#17 Amp\Dns\UnixConfigLoader->loadConfig() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:329]
#18 Amp\Dns\BasicResolver->Amp\Dns\{closure}()
#19 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#20 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#21 Amp\call() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:330]
#22 Amp\Dns\BasicResolver->reloadConfig() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:89]
#23 Amp\Dns\BasicResolver->Amp\Dns\{closure}()
#24 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#25 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#26 Amp\call() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:166]
#27 Amp\Dns\BasicResolver->resolve() called at [/app/vendor/amphp/dns/lib/functions.php:46]
#28 Amp\Dns\resolve() called at [/app/vendor/amphp/socket/src/functions.php:90]
#29 Amp\Socket\{closure}()
#30 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#31 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#32 Amp\call() called at [/app/vendor/amphp/socket/src/functions.php:179]
#33 Amp\Socket\connect() called at [/app/vendor/amphp/websocket-client/src/Rfc6455Connector.php:31]
#34 Amp\Websocket\Client\Rfc6455Connector->Amp\Websocket\Client\{closure}()
#35 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#36 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#37 Amp\call() called at [/app/vendor/amphp/websocket-client/src/Rfc6455Connector.php:58]
#38 Amp\Websocket\Client\Rfc6455Connector->connect() called at [/app/vendor/amphp/websocket-client/src/functions.php:52]
#39 Amp\Websocket\Client\connect() called at [/app/src/demo.php:41]
#40 Amp\Parallel\Context\Internal\Thread::{closure}()
#41 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#42 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:123]
#43 Amp\Loop\Driver->tick() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:72]
#44 Amp\Loop\Driver->run() called at [/app/vendor/amphp/amp/lib/Loop.php:84]
#45 Amp\Loop::run() called at [/app/src/demo.php:52]
#46 Amp\Parallel\Context\Internal\Thread::{closure}() called at [/app/vendor/amphp/amp/lib/functions.php:60]
#47 Amp\call() called at [/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:129]
#48 Amp\Parallel\Context\Internal\Thread->execute() called at [/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:102]
#49 Amp\Parallel\Context\Internal\Thread->Amp\Parallel\Context\Internal\{closure}()
#50 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#51 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:123]
#52 Amp\Loop\Driver->tick() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:72]
#53 Amp\Loop\Driver->run() called at [/app/vendor/amphp/amp/lib/Loop.php:84]
#54 Amp\Loop::run() called at [/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:108]
#55 Amp\Parallel\Context\Internal\Thread->run()
Tick from thread: 0
Internal thread running: 139956959835904 (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:86)
The second thread *904
is indeed constructed by DNS resolver, it is constructed before first tick (because of using Loop::run()
) and is run after first tick. Okay.
Tick from thread: 1
Tick from thread: 2
Tick from thread: 3
Tick from thread: 4
Joining thread: 139956973586176 (/app/vendor/amphp/parallel/lib/Context/Thread.php:229)
Ticker stopped
Connection is open: YES
Connection is open: NO
Out of thread loop
Worker shutdown started: Amp\Parallel\Context\Thread (/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:44)
Joining thread: 139956959835904 (/app/vendor/amphp/parallel/lib/Context/Thread.php:229)
Thread joined: 139956959835904 (/app/vendor/amphp/parallel/lib/Context/Thread.php:251)
Thread joined: 139956973586176 (/app/vendor/amphp/parallel/lib/Context/Thread.php:251)
Thread joined
Out of loop
We've send 'stop'
string to first thread and then call join() for the first thread
, then shutdown callback is triggered that "joins" second thread (in fact it stays alive) and then it "joins" first thread (in fact it also stays alive).
So, everything looks fine except for physical threads left alive for some hidden reason.
Experiment 2: WITHOUT nested Loop::run()
(just commented it out)
Pthreads version: 3.2.1dev
Program started
Loop started
Internal thread constructed (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:44)
#0 Amp\Parallel\Context\Internal\Thread->__construct() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:160]
#1 Amp\Parallel\Context\Thread->start() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:70]
#2 Amp\Parallel\Context\Thread::Amp\Parallel\Context\{closure}()
#3 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#4 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#5 Amp\call() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:72]
#6 Amp\Parallel\Context\Thread::run() called at [/app/src/demo.php:56]
#7 {closure}()
#8 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#9 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:123]
#10 Amp\Loop\Driver->tick() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:72]
#11 Amp\Loop\Driver->run() called at [/app/vendor/amphp/amp/lib/Loop.php:84]
#12 Amp\Loop::run() called at [/app/src/demo.php:64]
Internal thread running: 140093791782656 (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:86)
Thread started
Same picture as in first experiment.
Thread loop started
Worker constructed: Amp\Parallel\Context\Thread (/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:42)
Internal thread constructed (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:44)
#0 Amp\Parallel\Context\Internal\Thread->__construct() called at [/app/vendor/amphp/parallel/lib/Context/Thread.php:160]
#1 Amp\Parallel\Context\Thread->start() called at [/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:105]
#2 Amp\Parallel\Worker\TaskWorker->Amp\Parallel\Worker\{closure}()
#3 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#4 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#5 Amp\call() called at [/app/vendor/amphp/parallel/lib/Worker/TaskWorker.php:129]
#6 Amp\Parallel\Worker\TaskWorker->enqueue() called at [/app/vendor/amphp/parallel/lib/Worker/DefaultPool.php:152]
#7 Amp\Parallel\Worker\DefaultPool->enqueue() called at [/app/vendor/amphp/file/lib/ParallelDriver.php:50]
#8 Amp\File\ParallelDriver->runFileTask()
#9 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#10 Amp\Coroutine->__construct() called at [/app/vendor/amphp/file/lib/ParallelDriver.php:286]
#11 Amp\File\ParallelDriver->get() called at [/app/vendor/amphp/file/lib/functions.php:339]
#12 Amp\File\get() called at [/app/vendor/amphp/dns/lib/UnixConfigLoader.php:27]
#13 Amp\Dns\UnixConfigLoader->Amp\Dns\{closure}()
#14 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#15 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#16 Amp\call() called at [/app/vendor/amphp/dns/lib/UnixConfigLoader.php:78]
#17 Amp\Dns\UnixConfigLoader->loadConfig() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:329]
#18 Amp\Dns\BasicResolver->Amp\Dns\{closure}()
#19 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#20 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#21 Amp\call() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:330]
#22 Amp\Dns\BasicResolver->reloadConfig() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:89]
#23 Amp\Dns\BasicResolver->Amp\Dns\{closure}()
#24 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#25 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#26 Amp\call() called at [/app/vendor/amphp/dns/lib/BasicResolver.php:166]
#27 Amp\Dns\BasicResolver->resolve() called at [/app/vendor/amphp/dns/lib/functions.php:46]
#28 Amp\Dns\resolve() called at [/app/vendor/amphp/socket/src/functions.php:90]
#29 Amp\Socket\{closure}()
#30 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#31 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#32 Amp\call() called at [/app/vendor/amphp/socket/src/functions.php:179]
#33 Amp\Socket\connect() called at [/app/vendor/amphp/websocket-client/src/Rfc6455Connector.php:31]
#34 Amp\Websocket\Client\Rfc6455Connector->Amp\Websocket\Client\{closure}()
#35 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#36 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#37 Amp\call() called at [/app/vendor/amphp/websocket-client/src/Rfc6455Connector.php:58]
#38 Amp\Websocket\Client\Rfc6455Connector->connect() called at [/app/vendor/amphp/websocket-client/src/functions.php:52]
#39 Amp\Websocket\Client\connect() called at [/app/src/demo.php:41]
#40 Amp\Parallel\Context\Internal\Thread::{closure}()
#41 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#42 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/functions.php:66]
#43 Amp\call() called at [/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:129]
#44 Amp\Parallel\Context\Internal\Thread->execute() called at [/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:102]
#45 Amp\Parallel\Context\Internal\Thread->Amp\Parallel\Context\Internal\{closure}()
#46 Generator->current() called at [/app/vendor/amphp/amp/lib/Coroutine.php:41]
#47 Amp\Coroutine->__construct() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:123]
#48 Amp\Loop\Driver->tick() called at [/app/vendor/amphp/amp/lib/Loop/Driver.php:72]
#49 Amp\Loop\Driver->run() called at [/app/vendor/amphp/amp/lib/Loop.php:84]
#50 Amp\Loop::run() called at [/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:108]
#51 Amp\Parallel\Context\Internal\Thread->run()
Internal thread running: 140093708826368 (/app/vendor/amphp/parallel/lib/Context/Internal/Thread.php:86)
Tick from thread: 0
Okay, we don't use nested loop and thus we're getting here before first tick.
Tick from thread: 1
Tick from thread: 2
Tick from thread: 3
Joining thread: 140093791782656 (/app/vendor/amphp/parallel/lib/Context/Thread.php:229)
Ticker stopped
Connection is open: YES
Connection is open: NO
Out of thread loop
Thread joined: 140093791782656 (/app/vendor/amphp/parallel/lib/Context/Thread.php:251)
Thread joined
Out of loop
Shutdown callback is not triggered at all (and thus no even attempt to join the DNS thread *368
), but why? What changed but executing the nested loop callback before the first tick?
I tried looking into this some more, but I'm not really sure what is going on here. I'm not terribly motivated to investigate much further as ext-thread
is no longer going to be updated, so I will probably deprecate everything having to do with the extension in upcoming releases of amphp/sync
and amphp/parallel
. I would recommend trying out ext-parallel
, which is now supported by amphp/parallel
v1.2.
Hello! My application needs to talk with WebSocket server while it's main thread is blocked, so I used amphp/websocket:0.2.2 combined with amphp/parallel:0.2.5 and krakjoe/pthreads:3.1.7dev to do it from separate thread. Everything goes fine (successfull communication with server, I mean) except for closing the thread. I used the following minimalistic script to investigate the problem:
I also used the following dockerfile to run the script:
It produces the following output:
But the script hangs forever. If I comment out all
$connection
stuff, the program terminates okay. Further investigation withtop -H
revealed that opening a connection starts one more thread that doesn't finish after calling$connection->close()
, and probably that "third" thread keeps "second" thread from finishing. Is there some workaround on this situation? Is this a bug or maybe I'm just doing something wrong?