189 lines
7.5 KiB
Java
189 lines
7.5 KiB
Java
|
import java.util.concurrent.atomic.AtomicLong;
|
||
|
|
||
|
// V0.3 - PM 17/09/21
|
||
|
|
||
|
interface Incrémenteur extends Runnable{
|
||
|
void incr();
|
||
|
/* Boucle d'incrémentation effectuée par un processus (thread).
|
||
|
* Le principe/objectif est de réaliser cette boucle, comportant un même nombre
|
||
|
* d'incrémentations en suivant différents schémas pour maintenir la cohérence
|
||
|
* (ou pas) et de comparer ces schémas en termes de correction et d'efficacité
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
public class IncrMes {
|
||
|
|
||
|
// static long cpt = 0L;
|
||
|
static volatile long cpt = 0L;
|
||
|
// static final long NB_IT = 1000L; //Nb d'itérations de la boucle externe
|
||
|
// static final long NB_IT_INTERNES = 1000000L; //Nb d'itérations de la boucle interne
|
||
|
static final long NB_IT = 10L; //Nb d'itérations de la boucle externe
|
||
|
static final long NB_IT_INTERNES = 100L; //Nb d'itérations de la boucle interne
|
||
|
static long Attente_ms = 2L;
|
||
|
static final int Attente_nano = 0;
|
||
|
static Thread[] activités; // Tableau des processus
|
||
|
static Object mutex = new Object(); // pour les blocs synchronized
|
||
|
|
||
|
static void lancer(int nbA, Incrémenteur r) {
|
||
|
// Initialisation du/des compteur(s) incrémentés
|
||
|
cpt = 0L;
|
||
|
/* Création et lancement des threads.
|
||
|
* Chaque thread exécute le même code, qui est la méthode run() d'une classe
|
||
|
* implantant un Incrémenteur (autrement dit un schéma de réalisation particulier
|
||
|
* de la boucle dincrémentation)
|
||
|
*/
|
||
|
|
||
|
for (int i = 0; i < nbA ; i++) {
|
||
|
try {
|
||
|
IncrMes.activités[i] = new Thread(r,"t"+i);
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
System.out.println(e);
|
||
|
}
|
||
|
IncrMes.activités[i].start();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void finir() {
|
||
|
// Attente de la terminaison des différents threads lancés
|
||
|
for (int i = 0; i < IncrMes.activités.length ; i++) {
|
||
|
try {
|
||
|
IncrMes.activités[i].join();
|
||
|
}
|
||
|
catch (InterruptedException e)
|
||
|
{
|
||
|
System.out.println(e);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void main(String[] args) {
|
||
|
int nbActivités = 3;
|
||
|
int nbMesures = 6;
|
||
|
int i = 0;
|
||
|
long départ, fin;
|
||
|
boolean mutex = true;
|
||
|
|
||
|
// Chargement des paramètres saisis en ligne de commande
|
||
|
if (args.length == 3) {
|
||
|
try {
|
||
|
nbActivités = Integer.parseInt (args[0]);
|
||
|
Attente_ms = Integer.parseInt (args[1]);
|
||
|
nbMesures = Integer.parseInt (args[2]);
|
||
|
}
|
||
|
catch (NumberFormatException nfx) {
|
||
|
Attente_ms = 0;
|
||
|
}
|
||
|
if ((nbActivités < 1) || (Attente_ms < 1) || (nbMesures < 1)) {
|
||
|
System.out.println("Usage : IncrMes <Nb activités> <durée pause (ms)> <nbMesures>,"
|
||
|
+"avec Nb activités, durée pause, nbMesures >= 1");
|
||
|
System.exit (1);
|
||
|
}
|
||
|
} else {
|
||
|
System.out.println("Nb d'arguments ≠ 3. Exécution avec 6 mesures, 3 activités et 2 ms de pause");
|
||
|
}
|
||
|
|
||
|
activités = new Thread[nbActivités];
|
||
|
|
||
|
for (int it=1; it<=nbMesures; it++) { //
|
||
|
// Mesure itérée, pour éviter des écarts trop importants sur les premières mesures
|
||
|
// (du fait de possibles optimisations : processeur, cache, compilateur).
|
||
|
// Idée = retenir une moyenne des dernières mesures.
|
||
|
|
||
|
// Boucle séquentielle : NB_IT x NB_IT_INTERNES x nbActivités itérations
|
||
|
cpt=0L;
|
||
|
départ = System.nanoTime();
|
||
|
for (long li = 0; li < nbActivités*IncrMes.NB_IT; li++) {
|
||
|
for (long j = 1; j<=IncrMes.NB_IT_INTERNES; j++) {
|
||
|
IncrMes.cpt=IncrMes.cpt+j/j;
|
||
|
// j/j pour tenter d'éviter les optimisations du compilateur
|
||
|
}
|
||
|
try {
|
||
|
Thread.sleep(IncrMes.Attente_ms, IncrMes.Attente_nano);
|
||
|
// sleep pour modéliser un temps de calcul sans conflit d'accès et...
|
||
|
// pour tenter d'éviter les optimisations du cache
|
||
|
}
|
||
|
catch (InterruptedException ie)
|
||
|
{
|
||
|
System.out.println("InterruptedException : " + ie);
|
||
|
}
|
||
|
}
|
||
|
fin = System.nanoTime();
|
||
|
//System.out.print((fin-départ)/1000000L + ", ");
|
||
|
System.out.println("Durée exécution mono : " + (fin-départ)/1000000L);
|
||
|
System.out.println();
|
||
|
|
||
|
// Exemple de mesure avec IncrémenteurNonSync
|
||
|
départ = System.nanoTime();
|
||
|
// Lancement de nbActivités processus effectuant
|
||
|
// chacun NB_IT x NB_IT_INTERNES itérations
|
||
|
lancer(nbActivités, new IncrémenteurNonSync());
|
||
|
finir();
|
||
|
fin = System.nanoTime();
|
||
|
//System.out.print((fin-départ)/1000000L + ", ");
|
||
|
System.out.println("Durée exécution non synchronisée (ms): " + (fin-départ)/1000000L);
|
||
|
System.out.println();
|
||
|
|
||
|
// Compléter ici, sur le modèle précédent (lignes 112-120, (ou éditer la ligne 116)
|
||
|
//en définissant et mesurant différents Incrémenteur
|
||
|
// de manière analogue à ce qui est fait pour IncrémenteurNonSync
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class IncrémenteurNonSync implements Incrémenteur {
|
||
|
// class IncrémenteurNonSync extends AtomicLong implements Incrémenteur {
|
||
|
/* Exemple d'incrémenteur :
|
||
|
-la méthode incr effectue les incrémentations sans gérer les conflis d'accès au compteur
|
||
|
- la méthode run() appelle incr()
|
||
|
*/
|
||
|
|
||
|
public synchronized void incr_sync(long j){
|
||
|
IncrMes.cpt=IncrMes.cpt+j/j;
|
||
|
}
|
||
|
|
||
|
public synchronized void interne(long i) {
|
||
|
for (long j = 1; j<=IncrMes.NB_IT_INTERNES; j++) {
|
||
|
// incrémentation élémentaire
|
||
|
IncrMes.cpt=IncrMes.cpt+j/j;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void incr() {
|
||
|
// boucle imbriquée pour permettre (éventuellement) de tester différents
|
||
|
// grains de synchronisation
|
||
|
for (long i = 0L; i < IncrMes.NB_IT; i++) {
|
||
|
// boucle interne
|
||
|
for (long j = 1; j<=IncrMes.NB_IT_INTERNES; j++) {
|
||
|
// incrémentation élémentaire
|
||
|
incr_sync(j);
|
||
|
// IncrMes.cpt=IncrMes.cpt+j/j;
|
||
|
}
|
||
|
// interne(i);
|
||
|
try {
|
||
|
Thread.sleep(IncrMes.Attente_ms, IncrMes.Attente_nano);
|
||
|
}
|
||
|
// Attente depour éviter l'utilisation du cache et modéliser
|
||
|
// une partie du calcul sans conflit.
|
||
|
// Vous pouvez (éventuellement) commenter l'attente
|
||
|
// pour voir l'effet (intéressant) du mécanisme de cache,
|
||
|
// ou encore modifier la valeur de l'attente pour voir
|
||
|
// l'effet du grain de l'exclusion mutuelle sur les temps
|
||
|
// d'exécution
|
||
|
catch (InterruptedException ie)
|
||
|
{
|
||
|
System.out.println("InterruptedException : " + ie);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void run() {
|
||
|
// afficher éventuellement la valeur du compteur avant/après
|
||
|
// pour vérifier la cohérence des incrémentations
|
||
|
System.out.println("Thread " + Thread.currentThread().getName() + " part de : " + IncrMes.cpt);
|
||
|
this.incr();
|
||
|
System.out.println("Thread " + Thread.currentThread().getName() + " finit à : " + IncrMes.cpt);
|
||
|
}
|
||
|
}
|