8
votes

Les objets de fil de pthread réinitialisent leur état

Travailler récemment avec l'extension Pthreads , j'ai découvert une anomalie. J'ai un objet simple avec un état interne: xxx pré>

maintenant j'ai créé une classe de thread qui fait quelque chose avec cet objet: p>

$sum = new Sum();
$thread = new MyThread($sum);
$thread->start();
$thread->join();
echo $sum->getValue();


0 commentaires

3 Réponses :


1
votes

Votre problème est que vous accédez à la variable du fil principal et du fil mythead. La CPU met en cache la variable et elle est mise à jour dans le cache pour mythread mais pas dans le cache pour le fil principal, de sorte que vos deux threads ne voient jamais les autres changements de fil. En Java / C, etc. Il y a le mot clé volatil mais je ne sais pas si cela existe en PHP.

Je pense que vous devriez essayer d'appeler les méthodes en somme synchronisée ( http: // php .NET / Manual / fr / thread.Synchronized.php ) p>

Par exemple, au lieu de: P>

        $this->synchronized(function($thread){
            $thread->sum->add(5);
        }, $this);


5 commentaires

Nonono Vous définissez $ SUM = nouvelle somme () en dehors du thread SO $ SUM-> La valeur appartient au fil principal.


Au lieu de passer une somme au fil, vous pouvez essayer de créer l'objet somme à l'intérieur du fil. Si cela fonctionne, je suis juste sinon, eh bien, vous savez;)


:-) Je viens de faire ça: insérer $ ceci-> somme = nouvelle somme (); comme première ligne de la méthode de course (). Mais c'est toujours le même résultat.


Si la solution dans la réponse ne fonctionne pas, je pense que vous venez de trouver un bogue dans Pthread.


Il semble que vous utilisiez une ancienne version de Pthreads. Sur php.net, vous pouvez voir que cette fonction est disponible depuis que Pthreads 0.40. (En outre: il semble que toutes les fonctionnalités de synchronisation dans Pthreads ont été ajoutées à la version 0.40 afin que vous deviez vraiment mettre à jour php / pthreads)



17
votes

Tout objet non descendu d'une définition de Pthreads sera sérialisé lors de la définition d'un membre d'un objet issu de Pthreads.

Opérations telles que + = et [] Utilisez des pointeurs en interne, la sérialisation est incompatible avec des pointeurs pour d'autres objets. Dans le manuel de la page Introduction, il stipule que tout objet destiné à être manipulé par plusieurs contextes devrait s'étendre sur l'empilable, le thread ou le travailleur, comme P> xxx pré>

si la somme n'était pas utilisée Pointeurs Vous auriez la possibilité de récupérer la référence de l'objet fileté après une jointure. p>

Ce sont des opérations simples, vous n'êtes pas obligé de synchroniser. La seule fois que vous devriez synchroniser, c'est lorsque vous envisagez d'attendre sur un objet ou de notifier une. P>

Les objets groupés avec Pthreads sont très plus adaptés à cet environnement et ne sont jamais sérialisés. P>

Veuillez lire l'intro dans le manuel et tous les exemples des méthodes que vous souhaitez utiliser pour déterminer exactement ce que c'est quoi, puis n'hésitez pas à demander pourquoi :) p>

Je sais que les utilisateurs de PHP AREN Il avait l'habitude de devoir faire des recherches, mais nous repoussons l'enveloppe ici, vous trouverez que vous trouverez des moyens corrects de faire les choses de manière incorrecte, la plupart d'entre elles sont documentées dans des exemples et tout ce qui n'est pas sûr que je ne suis sûr pas être extraite de moi dessus et finalement, trouvez-moi que c'est la voie à la documentation. P>

Je ne sais pas si l'exemple que vous avez donné était de tester des objets en particulier, mais le code que vous avez fourni n'est pas nécessaire de ne pas être deux objets et de ne pas avoir besoin de Il s'agit de deux objets, considérez les éléments suivants: p> xxx pré>

Il peut être utile de voir quelques fonctionnalités supplémentaires en action avec une explication, donc Voici, voici un exemple similaire à vous: P>

<?php
class MyThread extends Thread {
    public $sum;

    public function __construct() {
        $this->sum = 0;
    }

    public function run(){
        for ($i=0; $i < 10; $i++) {
            $this->add(5);

            $this->writeOut("[%d]: %d\n", $i, $this->sum);
        }

        $this->synchronized(function($thread){
            $thread->writeOut("Sending notification to Process from %s #%lu ...\n", __CLASS__, $thread->getThreadId());
            $thread->notify();
        }, $this);
    }

    public function add($num) { $this->sum += $num; }
    public function getValue() { return $this->sum; }

    /* when two threads attempt to write standard output the output will be jumbled */
    /* this is a good use of protecting a method so that 
        only one context can write stdout and you can make sense of the output */
    protected function writeOut($format, $args = null) {
        $args = func_get_args();
        if ($args) {
            vprintf(array_shift($args), $args);
        }
    }
}

$thread = new MyThread();
$thread->start();

/* so this is synchronization, rather than joining, which requires an actual join of the underlying thread */
/* you can wait for notification that the thread is done what you started it to do */
/* in these simple tests the time difference may not be apparent, but in real complex objects from */
/* contexts populated with more than 1 object having executed many instructions the difference may become very real */
$thread->synchronized(function($thread){
    if ($thread->getValue()!=50) {
        $thread->writeOut("Waiting for thread ...\n");
        /* you should only ever wait _for_ something */
        $thread->wait();
        $thread->writeOut("Process recieved notification from Thread ...\n");
    }
}, $thread);

var_dump($thread->getValue());
?>


4 commentaires

Oui, ce code dans une classe était exactement ce que j'ai suggéré à des fins de test. Je pense qu'il a besoin de deux classes car il veut compter de multiples threads.


J'ai étendu la réponse pour couvrir cette possibilité ... l'utilisation aussi peu que possible est l'ordre de la journée lorsque vous travaillez avec un multi-threading. Une mesure de l'efficacité n'est pas du nombre de threads que votre application utilise, mais à quel point il utilise le moins de threads possible pour obtenir le travail effectué dans le temps le plus court.


Il y a même des avantages à prendre cette promenade pour la première fois dans PHP, tant de préoccupations dans d'autres langues ne sont tout simplement pas là dans Pthreads. Vos hypothèses qui peuvent être fidèles pour d'autres langues, ne s'appliquent pas ici, vous pouvez le voir par la manière dont vos pensées originales compliquées et en contrastent intégralement la simplification des solutions réelles. Mais il n'est pas nécessaire de ne pas être simple, c'est aussi simple ou aussi complexe que l'utilisateur l'écrit, quelque chose qui n'est pas présent dans d'autres API de filetage, ils sont tous, compliqués, peu importe quoi.


@ th3falc0n: Exactement. Je joue juste ici. Mon premier test - tout dans la classe de fil - a fonctionné bien. J'ai donc essayé la prochaine étape - injecter un objet - qui a échoué. Mais maintenant je sais à propos de cette chose empilable ...



0
votes

Je pensais que je fais quelque chose de mal aussi. Comme mentionné [] et d'autres opérations utilisant des pointeurs ne fonctionneront pas. Ceci est la solution de contournement: xxx

Ceci fonctionne comme nous utilisons [] opération sur une variable de fonction temporaire et que nous la définissons comme une variable de classe.

meilleur exemple pourquoi Il est nécessaire: xxx

afin que nous puissions utiliser et ajouter de nouveaux éléments à la variable dans plusieurs fonctions. La même chose fonctionnera pour + = et d'autres opérateurs, mais vous avez besoin de la variable temporaire pour cela.

Fonction facile à prolonger pour cette option: xxx

eval pourrait travailler ici mais je trouve cela beaucoup plus sûr.


0 commentaires