PHP - Aborting or Pausing pthread

How to interrupt a thread from the main context?

In the fragment below - how could one stop the action that the thread does without destroying it?

class ReadFileThread extends Thread
{
    public function __construct($file, $chunk = 1024)
    {
        $this->file = $file;

        $this->chunk = $chunk;
    }

    public function run()
    {
        if(is_file($this->file) && is_readable($this->file))
        {
            $fh = fopen($this->file, 'rb');

            while(!feof($fh))
            {
                $content = fread($fh, $this->chunk);
            }

            fclose($fh);
        }
    }
}

$num = 10;
$threads = [];

for($i = 0; $i < $num; $i++)
{
    $thread = new ReadFileThread('/path/to/10gig_file.txt', 1024);

    $threads[] = $thread;

    // I start the thread, now it detached from the main context and is reading the file asynchronously
    $thread->start();
}

// The interesting part - I want to random 1 thread whose operation of file reading I want to interrupt
$to_interrupt = $threads[rand(0, $num)];

// How to interrupt the thread without destroying it? I want its context preserved
+4
source share
3 answers

RandomSeeds answer is close, but open to race conditions.

<?php
class FileReader extends Thread {
    public $file;
    public $pause;

    public function __construct($file) {
        $this->file = $file;
        $this->pause = false;
    }

    public function run() {
        if (($handle = fopen($this->file, "rb"))) {
            $len = 0;
            do {
                $this->synchronized(function(){
                    if ($this->paused) {
                        printf(
                            "\npausing %lu ...\n", $this->getThreadId());
                        $this->wait();
                    }
                });

                $data = fread($handle, 1024);
                $len += strlen($data);

                if (($len % 2) == 0) {
                    printf( 
                        "\r\rread %lu", $len);
                }
            } while (!feof($handle));

            fclose($handle);
        }
    }

    public function pause() {
        return $this->synchronized(function(){
            return ($this->paused = true);
        });
    }

    public function unpause() {
        return $this->synchronized(function(){
            $this->paused = false;      
            if ($this->isWaiting()) {
                return $this->notify();
            }
        });
    }
}

function do_something($time) {
    $start = time();

    while (($now = time()) < ($start + $time)) {
        usleep(100);
        if (($now % 2) == 0) {
            echo ".";
        }
    }

    echo "\n";
}

$reader = new FileReader("/path/to/big/file.ext");
$reader->start();

sleep(2);
$reader->pause();
do_something(rand(2, 4));
$reader->unpause();
sleep(2);
$reader->pause();
do_something(rand(2, 4));
$reader->unpause();
sleep(2);
$reader->pause();
do_something(rand(2, 4));
$reader->unpause();
?>

It is important that the variables used for synchronization are ever access only in synchronized blocks, I omitted the stop / quit function implementation, but the logic is almost the same as the RandomSeeds example shows.

The race conditions are hidden inside:

public function mine($data) {
    /* anyone can set doSynchronization at any time */
    if ($this->doSynchronization) {

        $this->synchronize(function(){
            /* checking the predicate in here is safer */
            $this->wait();
        });
    }
}

Good:

public function mine($data) {
    $this->synchronize(function(){
        if ($this->doSynchronization) {
            $this->wait();
        }
    });
}

Extreme:

public function mine($data) {
    $this->synchronize(function(){
        while ($this->doSynchronization) {
            $this->wait();
        }
    });
}

posix , , . , , , pthread_cond_wait; , , ... ; , , , - , , , , ( - , die - ), ...

+9

AFAIK , . , .

:

<?php

class MyThread extends Thread {

    private $pauseRequested = false;
    private $stopRequested = false;

    public function pause() {
        $this->synchronized(function($thread){
            $thread->pauseRequested = true;
        }, $this);
    }

    public function resume() {
        $this->synchronized(function($thread){
            $thread->pauseRequested = false;
            $thread->notify();
        }, $this);

    }

    public function stop() {
        $this->synchronized(function($thread){
            $thread->stopRequested = true;
        }, $this);
    }

    public function run() {
        echo 'Thread started!' . PHP_EOL;
        while (!$this->stopRequested) {

            // do the actual work
            echo 'Working...';
            sleep(1);

            // check if we have been requested to pause
            $this->synchronized(function($thread){
                if ($this->pauseRequested) {
                    echo 'Paused...';
                    $thread->wait(); // this is where the magic happens
                }
            }, $this);
        }

        if ($this->stopRequested) {
            echo PHP_EOL . 'Stopped!' . PHP_EOL;
        }
    }
}


$t = new MyThread();
$t->start();
sleep(5);

$t->pause();
sleep(2);

$t->resume();
sleep(5);

$t->stop();

// wait for $t to complete
$t->join(); 

?>
+2

Pthreads, tbh have never been used, but have you tried to make a public boolean flag inside a thread class?

0
source

All Articles