PHP pthreads can't kill thread (& timeout realization) - php

I have an example code. What it does is visiting pages. I want to make timeout for thread execution and shut it down when it hangs too long. I thought that there is built-in methods to implement that. Also, i've tried to do it by my own with time() function. But there is another problem. At this point $workers[$i]->kill(); script hangs and kill() method returns false so i can't shutdown thread by force. What is happening and what am i doing wrong?
Thank you!
<?php
/**
* Author: Abu Ashraf Masnun
* URL: http://masnun.me
*/
//define("TMT",3);
class WorkerThreads extends Thread
{
private $workerId;
public function __construct($string)
{
$this->command_string = trim($string);
}
public function run()
{
echo $this->command_string." ".Thread::getCurrentThreadId()."\n";
//sleep(rand(0, 3));
$str = "C:\\Users\\Alex\\Desktop\\2web\\phantom\\phantomjs.exe C:\\Users\\Alex\\Desktop\\2web\\test.js ";
$url = $this->command_string;
$d = explode("://",$url);
$ex_str = $str." ".$url." > ".$d[1].".html";
//$ex_str = $str." ".$url;
//echo $ex_str;
//$ex_str = escapeshellarg($ex_str);
//echo $ex_str;
exec($ex_str, $out);
//print_r($out);
}
}
//$data = file('sites.txt');
$data_f = file('sites_x.txt');
print_r($data_f);
$data = array();
$data_size = count($data_f);
for($i = 0;$i<$data_size;$i++)
{
$info = explode(";",trim($data_f[$i]));
if($info[1] === 'y')
continue;
$data[] = $info[0];
}
print_r($data);
$data_size = count($data);
// Worker pool
$workers = [];
$t_count = 4;
$flag = 1;
$k = 0;
//echo "$data_size";
while($flag === 1)
{
/*
//echo "$k\n";
if($k >= $data_size)
{
//echo "111"; exit();
$flag = 0;
break 2;
}
*/
$c_w = count($workers);
if($c_w < $t_count)
{
for($i = $c_w; $i<$t_count - $c_w;$i++)
{
if($k >= $data_size)
{
$flag = 0;
break;
}
$workers[$i] = new WorkerThreads($data[$k]);
//echo $data[$k]."\n";
echo "worker $i started\n";
$workers[$i]->start();
$k++;
}
}
$c_w = count($workers);
for($i=0;$i<$c_w;$i++)
{
$workers[$i]->kill();
unset($workers[$i]);
echo "unset $i\n";
//var_dump($workers[$i]->isTerminated(), $workers[$i]->getTerminationInfo());
/*
if($workers[$i]->join())
{
//var_dump($workers[$i]->isTerminated(), $my->getTerminationInfo());
echo "joining $i\n";
unset($workers[$i]);
}
*/
}
}
?>

I ran into this problem today with pthreads 2.0.10.
After recompiling PHP from source to get ZTS support, I tried building pthreads (phpize, configure, make). Everything seemed OK until I ran make test. killed-info test failed after a 30 second timeout.
Solution for me was to compile the latest pthreads from the master branch on github.

Related

Connection lost during long time process to save records in database sqlite3 codeigniter

I have a heavy process which produce lots of records (>1000000) that should be save to the sqlite3 database in codeigniter.
The setting to connect to database in runtime is like this
$config['hostname'] = '';
$config['username'] = '';
$config['password'] = '';
$config['database'] = './application/database/' . $database_name;
$config['dbdriver'] = 'sqlite3';
$config['dbprefix'] = '';
$config['pconnect'] = false;
$config['db_debug'] = true;
$config['autoinit'] = false;
$config['cache_on'] = false;
$config['cachedir'] = '';
$config['stricton'] = false;
$config['char_set'] = 'utf8';
$config['dbcollat'] = 'utf8_general_ci';
$config['save_queries'] = true;
$config['failover'] = array();
my code in CI_Controller is
$counter = 0;
$this->load->model('db_model');
for ($j = 0; $j < $MAX_Y; $j++) {
for ($i = 0; $i < $MAX_X; $i++) {
// some process .....
// prepare $values
if ($counter > 20000) {
$this->db_model->insert($values, $config);
$counter = 0;
unset($values);
$values = array();
} else {
$counter++;
}
}
}
if ($counter > 0) {
$this->db_model->insert($values, $config);
}
my code in db_model is
class Db_model extends CI_Model
{
public function __construct()
{
parent::__construct();
set_time_limit(10000);
}
public function insert($data, $config)
{
$DB = null;
$DB = $this->load->database($config, TRUE);
$DB->initialize();
// $DB->busyTimeout(72000000);
$DB->trans_start();
$DB->insert_batch('tbl_name', $data);
$DB->trans_complete();
$DB->close();
}
}
During the saving records into table in sqlite3 database suddenly it stop writing the rest of records which is remain and table does not have all records which should have.
I think some thing is wrong with connection time out, and i should change some thing related to connection time out. but i did not find a good answer for this issue after couple of weeks.
Do like this: $db['default']['options'] = array(PDO::ATTR_TIMEOUT => 50000);
In config file: (application/config/database.php)
Refer this answer
This may be caused because of your code which is performed before inserting the data, which cause the server connection to break to save the resources.
The best way to do it is just close the connection and reconnect DB manually before the insert query using this:
$this->db->close();
$this->db->initialize();
Or
$this->db->reconnect();
Check: Reconnecting / Keeping the Connection Alive for reference.
You put the set_time_limit(10000); inside of the model. But you run over a loop in the CI_Controller, and I guess that the inserts them self are not long.
The time out won't happen in the model, it will happen in the controller. So try to change the CI_Controller like this:
$counter = 0;
$this->load->model('db_model');
set_time_limit(10000); //set time limit to the longest run of this script
for ($j = 0; $j < $MAX_Y; $j++) {
for ($i = 0; $i < $MAX_X; $i++) {
// some process .....
// prepare $values
if ($counter > 20000) {
$this->db_model->insert($values, $config);
$counter = 0;
unset($values);
$values = array();
} else {
$counter++;
}
}
}
if ($counter > 0) {
$this->db_model->insert($values, $config);
}
I got super tired of PHP timeouts and I started writing
"restart-able" programs. The basics...
$step=(int)$_SERVER["QUERY_STRING"];
switch($step) {
case 0:
/* SETUP */
redirect($_SERVER["PHP_SELF"]."?1";
case 1:
/* DO SOME WORK */
if (work<>done) {
redirect($_SERVER["PHP_SELF"]."?1";
} else {
exit;
}
}
function redirect($url,$seconds=0) {
$html="<html><head><meta http-equiv='refresh' content='$seconds; URL=$url'></head></html>";
echo $html;
exit();
}

Detecting a cycle in an array PHP

I'm running a simple script which puts an integer through the formula of the Collatz conjecture and adds the output of each step into an array.
I want to use a function to detect if there's a cycle in the array, using Floyd's algorithm. And though I feel like I'm not doing a bad job, I don't seem to get it right. At this moment I'm getting the error Trying to get property 'next' of non-object in C:\xampp\htdocs\educom\week3\functions.php on line 12
See my code below. Any feedback is greatly appreciated!
include("functions.php");
$n = $_POST['number'];
$step = 0;
$reeks1 = array();
$cycle = 0;
echo "Your entry is: ". $n ."<br><br>";
while($n!==1 && $cycle==0){
$cycle = detect_cycle(array($reeks1));
if($n % 2 == 0){
$n = $n / 2;
array_push($reeks1, "$n");
$step++;
echo $step .": ". $n ."<br>";
}else{
$n = ($n * 3) + 1;
array_push($reeks1, "$n");
$step++;
echo $step .": ". $n ."<br>";
}
}
functions.php:
function detect_cycle($node){
if ($node==NULL){
return FALSE;
}
$turtle = $node;
$rabbit = $node->next;
while($rabbit != NULL){
if($rabbit === $turtle){
return TRUE;
}elseif($rabbit->next == NULL){
return FALSE;
}else{
$turtle = $turtle->next;
$rabbit = $rabbit->next->next;
}
}
return FALSE;
}
Check this out. IMPORTANT I don't know is this according to your theory. but it won't give you errors if you use like this.
function detect_cycle($node){
if ($node==NULL){
return FALSE;
}
$turtle = $node;
$rabbit = $node[0];
while($rabbit != NULL){
if($rabbit === $turtle){
return TRUE;
}elseif($rabbit[0] == NULL){
return FALSE;
}else{
$turtle = $turtle[0]; // use the number of the element key starting from 0
$rabbit = $rabbit[0][1];
}
}
return FALSE;
}

Pausing PHP process via command line

I am running this via the command line. When the loop is running, is there any way I can pause the execution of the code? Ideal case would be that I could press a key to pause and then another key to resume. If I don't press the pause key then the loop continues until $i == 1000
<?php
echo "How long should the code sleep between increments?\n";
echo ">> ";
$sleep = trim(fgets(STDIN));
for ($i = 1; $i <= 1000; $i++) {
echo "$i\n";
sleep($sleep);
}
This is a heavily simplified example of my actual need for the code.
I don't sure my code is best solution or not but it work.
function checkResume()
{
$r = false;
while (!$r) {
if (fgets(STDIN) == "r") {
$r = true;
}
}
}
function checkPause()
{
$input = fgets(STDIN);
if (!empty($input) && $input == "p") {
return true;
}
return false;
}
echo "How long should the code sleep between increments?\n";
echo ">> ";
$sleep = trim(fgets(STDIN));
echo "\nStart ...\n";
stream_set_blocking(STDIN, false);
for ($i = 1; $i <= 1000; $i++) {
if (checkPause()) {
echo "wait for resume \n";
checkResume();
}
echo "$i\n";
sleep($sleep);
}
Hope this help.

Ball clock implemented in PHP spins out of control.

I'm trying to implement the ball clock (determine how many iterations an inputed number of balls in the initial queue would go before returning to its initial order) in php. I believe at this point my code is not recognizing when to stop. I'm using an SplQueue to represent the queue and keeping an int inside each ball that represents their order.
I believe the difficulty to be in traversing the $queue in the function hasTerminated(). The code runs, it just doesn't stop. An input of 30, for example (php script.php 30) should output 30 12 hour cycles to complete, but it does not terminate. I appreciate any and all ideas as to how to access the objects of the $queue and compare them without destroying the $queue. PHP is not a language I am very comfortable with.
<?php
class Ball {
static $counter = 0;
protected $index;
function __construct(){
$this->index = self::$counter;
self::$counter++;
}
function getIndex(){
return $this->index;
}
}
class Clock {
protected $queue;
protected $minuteTrack;
protected $fiveMinuteTrack;
protected $hourTrack;
protected $count;
protected $time = 0;
function __construct($num){
$this->queue = new \SplQueue;
$this->minuteTrack = new \SplStack;
$this->fiveMinuteTrack = new \SplStack;
$this->hourTrack = new \SplStack;
$this->count = $num;
for($i = 0; $i<$num; $i++){
$ball = new Ball();
$this->queue->enqueue($ball); //inefficient
}
}
function hasTerminated(){
$inOrder = true;
$prev = -1;
$q = clone $this->queue;
while($q->count() != 0){
$elt = $q->dequeue();
if($elt->getIndex() >= $prev){
$inOrder = false;
} else {
$prev = $elt->getIndex();
}
}
echo PHP_EOL;
if($inOrder){
echo 'It takes ' . $time . ' 12 hour cycles to return to the original ordering' . PHP_EOL;
exit(0);
} else {
echo 'Not finished yet' . PHP_EOL;
}
}
function run(){
while(true){
$ball = $this->queue->dequeue();
if(!$this->addBallToMinuteTrack($ball)){
if(!$this->addBallToFiveMinuteTrack($ball)){
if(!$this->addBallToHourTrack($ball)){
$this->queue->enqueue($ball);
}
}
}
}
}
function addBallToMinuteTrack($ball){
echo '1';
if($this->minuteTrack->count() < 4){
$this->minuteTrack->push($ball);
return true;
} else if( $this->minuteTrack->count() == 4){
for($i=0; $i<4; $i++){
$this->queue->enqueue($this->minuteTrack->pop()); //hate this
}
return false;
}
}
function addBallToFiveMinuteTrack($ball){
echo '5';
if($this->fiveMinuteTrack->count() < 11){
$this->fiveMinuteTrack->push($ball);
return true;
} else if( $this->fiveMinuteTrack->count() == 11){
for($i=0; $i<11; $i++){
$this->queue->enqueue($this->fiveMinuteTrack->pop());
}
return false;
}
}
function addBallToHourTrack($ball){
echo '60' . PHP_EOL;
if($this->hourTrack->count() < 11){
$this->hourTrack->push($ball);
return true;
} else if( $this->hourTrack->count() == 11){
for($i=0; $i<11; $i++){
$this->queue->enqueue($this->hourTrack->pop()); //hate this
}
$this->time = $this->time + 1; //In half day increments
$this->hasTerminated();
return false;
}
}
}
foreach (array_slice($argv, 1) as $arg) {
if(!is_numeric($arg)){
echo 'Arguments must be numeric' . PHP_EOL;
exit(1);
} else {
$clock = new Clock($arg);
$clock->run();
}
}
?>

GMP handle overflow

I have following PHP script which I call via CLI:
#!/usr/bin/php
<?php
$max_stellen = 10;
for ($base=2; $base<=62; $base++) {
for ($power=2; $power<=10; $power++) {
$result = array();
$max_base = gmp_pow($base, $max_stellen);
$x = gmp_init(0);
while ((gmp_cmp($x, $max_base) == -1)) {
$val = gmp_strval($x, $base);
$i = strlen($val);
$left = gmp_pow($x, $power);
$right = gmp_pow($base, $i);
$mod = gmp_mod($left, $right);
if (gmp_cmp($mod, $x) == 0) {
$result[] = $val;
}
unset($left);
unset($right);
unset($mod);
$x = gmp_add($x, 1); // !!! line 30
}
unset($x);
unset($max_base);
$res2 = array();
foreach ($result as &$r) {
$root = substr($r, -1);
$res2[$root][] = $r;
}
unset($result);
foreach ($res2 as $root => &$r) {
echo "X^${power}_${base}($root) = {".implode(', ', $r)."}\n";
}
unset($res2);
echo "\n";
}
}
After a short time (values base=6, power=9), I get following error message:
PHP Warning: gmp_add(): -2147483648 is not a valid GMP integer resource in ... on line 30
If I manually run the code with base=6, power=9, it works, so the error only happens when the loop is running multiple times.
The error message sounds like there are GMP handles allocated which are not freed when they are not used anymore. So after a short time, the handle is out of integer range. But how do I free GMP handles? I already tried to use unset() everywhere, and functions like gmp_free() or gmp_destroy() do not exist.
Update
Reported issue to PHP, since I believe that it is not an expected behavior: https://bugs.php.net/bug.php?id=69702

Categories