Utilisation de sémaphores ou de flock en mutualisé

Bonjour,

je veux utiliser une sémaphore pour protéger une partie critique de la concurrence sur un serveur mutualisé KimSufi.
J'ai d'abord utilisé les sémaphores proposées par PHP, ça marchait bien, mais parfois (peut-être parce-qu'elles sont partagées par tous les sites du serveur mutualisé) je me retrouve avec l'erreur suivante lorsque j'appelle `sem_get()` :
> Warning : sem_get() : failed for key [mon id] : no space left on device in [mon fichier php].

J'ai donc implémenté ma propre sémaphore en utilisant un fichier et la fonction "flock" qui permet d'implémenter un verrou exclusif bloquant comme dans le code ci-dessous.
Le code ci-dessous est un test que je peux lancer dans deux onglets simultanément. La sémaphore devrait permettre que le code entre `semAcquire()` et `semRelease()` s'exécute atomiquement. Ainsi, la première requête devrait compter de 1 à 100, et la deuxième requête devrait attendre que la première se termine puis compter de 101 à 200. Ce test fonctionne très bien sur Wamp Server mais ne fonctionne pas sur le serveur OVH :
Visiblement, la fonction `flock` retourne `true` directement même si un verrou a déjà été demandé.. Quelqu'un sait si c'est OVH qui n'implémente pas `flock` ? Ou est-ce un problème de configuration ? Qu'est-ce que je peux faire sinon ? Merci pour votre aide ! :slight_smile:


// Mes propres sémaphores puisque les sémaphores php ne marchent pas très bien en mutualisé…
function semAcquire() {
$sem = fopen("semaphore.txt", "w");
$fl = flock($sem, LOCK_EX);
echo $fl;
if($fl) {
fwrite($sem, getmypid());
} else {
die("Semaphore acquire error.");
}
return $sem;
}

function semRelease($sem) {
if(!flock($sem, LOCK_UN)) {
die("Semaphore release error.");
}
fclose($sem);
}

$sem = semAcquire();
for($j=0; $j < 100; $j++) {
for($i = 0; $i < 1000000; $i++) {

}
$n = file_get_contents("sem_test.txt");
$n++;
file_put_contents("sem_test.txt", $n);
echo "Compteur : $n
";
}
semRelease($sem);

echo "Fin!";

?>

Louis Durand

Quelle version de PHP utilises-tu ?

Version 5.6 !

Ce qui me choque, c'est que dans la function semAcquire :
* Tu fais un fopen
* Mais tu oublie le fclose

De même dans la function semRelease je mettrais d'abord un fopen

Non fclose est appelé dans `semRelease`, car je veux garder le verrou sur le fichier jusqu'à l'appel de `semRelease` !

Ah.. Je peux essayer effectivement de mettre un fclose semAcquire, puis un fopen dans semRelease, pourquoi pas. Je vais tester ça. (Pourtant ça marche tel quel sur Wamp.)

Autant je me suis trompé dans la lecture de tes fonctions. :frowning:
Ce que tu avais fait semble correct.

Pourquoi utilises-tu sem_test.txt comme fichier compteur et non semaphore.txt ?

De plus, rien n'empêche le 2ème script lancé de démarrer en même temps et d'écrire dans le fichier sem_test.txt

Bon alors j'ai fait les tests suivants :
- Switch sur php 7.0 : pareil
- Ajout d'un fclose dans semAcquire et fopen dans semRelease : pareil (ça marche sur wamp, mais ça ne marche pas sur le serveur)
:frowning:

`semaphore.txt` est mon fichier utilisé pour la sémaphore, celui sur lequel je mets le verrou.

`sem_test.txt` est juste un fichier utilisé dans le cadre du test, ici pour faire office de mémoire partagée entre les process. Comme ça on peut voir s'il est modifié par plusieurs process en cas de concurrence.


De plus, rien n'empêche le 2ème script lancé de démarrer en même temps et d'écrire dans le fichier semtest.txt_


Si justement : la sémaphore !
Si les deux scripts sont lancés à peu près simultanément, le premier qui appelle `flock` obtiendra le verrou sur le fichier `semaphore.txt`. Ensuite, le deuxième process, lorsqu'il va appeler flock, il sera **bloqué** tant que le verrou n'est pas levé, c'est-à-dire, tant que le premier process n'aura pas appelé semRelease, à la fin des 100 tours de boucles. Là, le second process peut mettre son verrou sur flock et entamer la partie critique.

$sem = semAcquire();

Il n'y a aucune analyse du retour de cet appel.

Le processus "for($j=0; $j < 100; $j++) {" peut s'exécuter en toute liberté.

flock est bloquant donc le deuxième processus va rester bloqué à la ligne `$fl = flock($sem, LOCK_EX);` jusqu'à ce que le verrou soit levé !
http://php.net/manual/fr/function.flock.php

Le code fonctionne, je l'ai testé sur Wamp Server, ça marche.

En fait ma question porte davantage sur :
Est-ce que flock fonctionne chez ovh, sur un mutualisé avec l'offre KimSufi ? Si non, pourquoi ? Si oui, comment le faire marcher chez moi ! Ou comment implémenter des sémaphores autrement.. ?

En tous cas merci pour votre aide !


flock est bloquant donc le deuxième processus va rester bloqué à la ligne $fl = flock($sem, LOCK_EX); jusqu'à ce que le verrou soit levé !
http://php.net/manual/fr/function.flock.php




C'est donc ce que cela veut dire ?

Sur quel cluster es-tu ?

De plus, en mutualisé, je ne suis pas sûr que deux lancements de scripts travaillent sur le même espace.

As-tu activé le CDN ?

Personnellement, je mettrais le FLAG dans une table SQL.

Oui c'est ça ! Si on met l'option LOCK_NB (NB pour Non Blocking j'imagine, alors la fonction ne bloque pas et renvoie juste false je crois, mais c'est le fait que la fonction soit bloquante qui m'intéresse justement !)

cluster017 visiblement.

CDN ? Visiblement non, "Options CDN" affiche "Non" dans le manager d'ovh.

Mmh intéressant, comment ferais-tu pour ta solution utilisant un FLAG avec SQL ?
Note que je ne peux pas utiliser juste des transactions SQL car dans ma partie critique, j'ai des requêtes SQL et des modifications de fichier, donc le système de sémaphore était le plus simple ET efficace :slight_smile:

Je suis d'accord avec ce que tu développes.

Pour le FLAG SQL :
Je créerai une table SQL avec deux champs : Id et FLAG.
* Le FLAG à 1 indiquerai un blocage d'opération pour un traitement donné.
* Le FLAG à 0 laisserai libre les opérations.

Ceci dit, j'essaierai d'abord avec un simple fichier qui contientrait ce FLAG.

Mmh oui mais comment reproduire cet effet "bloquant" où le deuxième script attend que le premier soit terminé et reprend son exécution ?
On pourrait faire un while qui vérifie l'état du flag en permanence mais ça me paraît lourd. Il me semble que l'implémentation sous-jacente à une fonction bloquante comme `flock` ou `sem_acquire` met le processus en pause et le reprend lorsque la ressource est libérée. (Du moins c'est ainsi que devraient être implémentées ce genre de fonctions)

Toujours d'accord avec toi, mais quand le cas NORMAL ne fonctionne pas on prend une rustine (Workaround, Fix). :slight_smile:

Haha effectivement, je pense que ce sera ma solution si je ne trouve pas une manière d'utiliser les sémaphores natives de php ou flock, mais c'est très frustrant d'avoir DEUX solutions propres et qu'aucune ne fonctionne pour aucune raison valable.. (Les sémaphores natives, à la rigueur, je peux comprendre sur un mutualisé, mais flock ???) En tous cas j'ai rien trouvé sur le net à propos de flock qui ne fonctionne pas. Donc c'est bizarre. Et je pense être en droit d'attendre d'OVH que les fonctions php fonctionnent. Donc je vais d'abord m'entretenir un peu avec l'assistance, et sinon, j'utiliserai un flag dans un while.

Merci pour ton aide !! Si tu trouves d'autres pistes n'hésite pas à partager ça ici bien sûr :slight_smile:

Malheureusement, à part les RUSTINES, je n'ai rien d'autre en rayon en ce moment. :smiley: