如何从主上下文中断线程的执行?
在下面的代码段中 - 如何在不破坏线程的情况下停止线程执行的操作?
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's 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
答案 0 :(得分:10)
RandomSeeds答案很接近,但对竞争条件开放。
<?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();
?>
重要的是,用于同步目的的变量只能在同步块中访问,我省略了stop / quit函数的实现,但它的逻辑与RandomSeeds示例显示的大致相同。
竞争条件潜伏在:
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();
});
}
}
好:
public function mine($data) {
$this->synchronize(function(){
if ($this->doSynchronization) {
$this->wait();
}
});
}
极限:
public function mine($data) {
$this->synchronize(function(){
while ($this->doSynchronization) {
$this->wait();
}
});
}
posix标准总是让你以极端的方式写它,我不是那么讨厌,不管你有什么用。这种极端代码的原因是,必须允许线程接收除正在等待的信号之外的信号,许多低电平信号可能导致线程从调用pthread_cond_wait唤醒;检查循环中的谓词就像防止规范所谓的虚假唤醒......但是这种极端措施也会导致不良副作用;这些线程接收低电平信号的原因是因为它们需要采取某种行动,忽略这很容易导致堆栈的不同部分死锁,因为它期望你的线程死掉(或做其他事情,当它被发出信号时,就是一个例子......
答案 1 :(得分:3)
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 :(得分:0)
从未使用过pthreads,tbh,但您是否尝试在线程类中创建一个公共布尔标志?