2017-09-22 5 views
0

Ich suche, einige Male (nbFois) mit Themen zu drucken. Ich habe es gemacht, aber es gibt ein Problem mit dem folgenden Code. Dies funktioniert nur, wenn alle Threads nbFois gleich sind.Alternate Thread print C

Hier funktioniert das mit nbAffichage [i] = 5 foreach thread. Aber wenn der nbAffichage zufällig ist (zB, der erste ist 3 ... der zweite ist 6); dann, wenn das erste Ende das zweite nicht starten kann.

/* Lancer les threads afficheurs */ 
    for (i = 0; i < nbThreads; i++) { 
    //nbAffichages[i] = rand() % NB_AFFICHAGES; 
    nbAffichages[i] = 5; 
    if ((etat = pthread_create(&idThdAfficheurs[i], NULL, 
           thd_afficher, &nbAffichages[i])) != 0) 
     thdErreur(etat, "Creation afficheurs", NULL); 
    } 

Die Druckfunktion

void *thd_afficher (void *arg) { 
    int i, j, nbLignes; 
    int *nbFois = (int *)arg; 
    int monMut=tMut.indiceT[iAffiche]; 
    iAffiche=(iAffiche+1)%nbThreads; 
    for (i = 0; i < *nbFois; i++) { 
    nbLignes = rand()% (*nbFois); 
    //nbLignes = 3; 
    //l'affichage est trop rapide pour voir la différence 
    pthread_mutex_lock (&tMut.m[monMut]);//demande accès 
    for (j = 0; j < nbLignes; j++) { 
     printf("Thread %lu, j'affiche %d-%d--------%d lignes\n", pthread_self(), i, j,nbLignes); 
     usleep(10); 
    } 
    pthread_mutex_unlock (&tMut.m[(monMut+1)%nbThreads]);//rend accès 
    } 
    /* Se terminer sans renvoyer de compte-rendu */ 
    pthread_exit((void *)NULL); 
} 

Die globale Struktur Gewinde

typedef struct ThreadId ThreadId; 
struct ThreadId 
{ 
    int indiceT[NB_THREADS_MAX]; 
    pthread_mutex_t m[NB_THREADS_MAX]; 
}; 

ThreadId tMut; 

Vielen Dank für Ihre Hilfe.

EDIT: Der gesamte Code

/* nbThread affichent un message a l'ecran 
    Parametre du programme : nbThread 
*/ 
#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <pthread.h> 

#define NB_THREADS_MAX 20 
//#define NB_FOIS   2 


typedef struct ThreadId ThreadId; 
struct ThreadId 
{ 
    int indiceT[NB_THREADS_MAX]; 
    pthread_mutex_t m[NB_THREADS_MAX]; 
}; 

ThreadId tMut;//variable de structure avec le tableau de threads et d'indice correespondant 
//Mutex ayant le droit d'écrire au début 
int iAffiche=0; 
int nbThreads=-1; 
/*---------------------------------------------------------------------*/ 
/* Afficher un message d'erreur en fonction du code erreur obtenu 
*/ 
void thdErreur(int codeErr, char *msgErr, void *codeArret) { 
    fprintf(stderr, "%s: %d soit %s \n", msgErr, codeErr, strerror(codeErr)); 
    pthread_exit(codeArret); 
} 

/*---------------------------------------------------------------------*/ 
/* Fonction executee par un thread : afficher un message un certain nombre 
    de fois nbFois a l'ecran, nbLignes lignes de messages ou nbLignes et 
    genere aleatoirement 
    Parametre de creation du thread : nbFois, le nombre d'affichages 
*/ 
void *thd_afficher (void *arg) { 
    int i, j, nbLignes; 
    int *nbFois = (int *)arg; 
    int monMut=tMut.indiceT[iAffiche]; 
    iAffiche=(iAffiche+1)%nbThreads; 
    for (i = 0; i < *nbFois; i++) { 
    //nbLignes = rand()% (*nbFois); 
    nbLignes = 3; 
    //l'affichage est trop rapide pour voir la différence 
    pthread_mutex_lock (&tMut.m[monMut]);//demande accès 
    for (j = 0; j < nbLignes; j++) { 
     printf("Thread %lu, j'affiche %d-%d--------%d lignes\n", pthread_self(), i, j,nbLignes); 
     usleep(10); 
    } 
    pthread_mutex_unlock (&tMut.m[(monMut+1)%nbThreads]);//rend accès 
    } 
    /* Se terminer sans renvoyer de compte-rendu */ 
    pthread_exit((void *)NULL); 
} 

/*---------------------------------------------------------------------*/ 
#define NB_AFFICHAGES 10 

int main(int argc, char*argv[]) { 
    pthread_t idThdAfficheurs[NB_THREADS_MAX]; 
    int i, etat; 

    int nbAffichages[NB_THREADS_MAX]; 
    if (argc != 2) { 
    printf("Usage : %s <Nb de threads>\n", argv[0]); 
    exit(1); 
    } 

    nbThreads = atoi(argv[1]); 
    if (nbThreads > NB_THREADS_MAX) 
    nbThreads = NB_THREADS_MAX; 

    //initialisation des mutex 
    for (int k = 0; k < nbThreads; k++){ 
    tMut.indiceT[k]=k; 
    pthread_mutex_init(&tMut.m[k],NULL);//tout les mutex init à 1 
    if(k!=0){ 
     pthread_mutex_lock (&tMut.m[k]);//On retire l'accès à tous les mutex sauf le premier 
    } 
    } 


    /* Lancer les threads afficheurs */ 
    for (i = 0; i < nbThreads; i++) { 
    //nbAffichages[i] = rand() % NB_AFFICHAGES; 
    nbAffichages[i] = 5; 
    if ((etat = pthread_create(&idThdAfficheurs[i], NULL, 
           thd_afficher, &nbAffichages[i])) != 0) 
     thdErreur(etat, "Creation afficheurs", NULL); 
    } 

    /* Attendre la fin des threads afficheur car si le thread principal 
    - i.e. le main() - se termine, les threads fils crees meurent aussi */ 
    for (i = 0; i < nbThreads; i++) 
    if ((etat = pthread_join(idThdAfficheurs[i], NULL)) != 0) 
     thdErreur(etat, "Join threads afficheurs", NULL); 

    printf ("\nFin de l'execution du thread principal \n"); 
    return 0; 
} 
+0

Ich sehe nicht, dass "iAffiche" irgendwo definiert wird. Auch 'int monMut = tMut.indiceT [iAffiche]; iAffiche = (iAffiche + 1)% nbThreads; 'ist nicht atomar, also könnten Sie mehrere Threads mit derselben iAffiche erhalten. – PeterT

+0

Was ist "iAffiche" und wo wird es deklariert (Speicherklasse?). Warum hat jeder Thread seinen eigenen Mutex, (sinnlos)? Warum schützen diese Mutex nur eine Druckschleife, (stdout hat sowieso eine interne Sperre)? –

+0

Ich habe den ganzen Code am Ende hinzugefügt – Minirock

Antwort

2

Sie haben eine Race-Bedingung auf den Zuordnungen zu iAffiche. Selbst wenn das gut geht, sperren deine Threads dann "ihren eigenen" Mutex (monMut), aber entsperren dann ihre Nachbarn! Es sieht so aus, als ob Sie ein Token auf der ganzen Linie weiterleiten möchten (was sehr wahrscheinlich fehlschlagen könnte, wenn die Threads eine unterschiedliche Anzahl von Wiederholungen durchlaufen wollen), aber Sie können solche Mutexes überhaupt nicht verwenden.

Sie könnten stattdessen ein Array von semaphores versuchen. Initialisiere sie auf 0 mit Ausnahme der ersten Threads, die 1 ergeben. Dann wird die gleiche Anzahl über alle Threads wiederholt, jeder Thread wartet auf seinen Semaphor, macht seine Arbeit (oder tut nichts, wenn seine nbAffichages Werte zu klein sind) und hebt dann den Semaphor des nächsten Threads hoch. Sie landen wieder im Ausgangszustand, wobei der Semaphorvektor (1,0,0, ...) ist.

+0

Ich soll die erste Nachricht von Thread 1 drucken ... dann die erste Nachricht von Thread 2. Dann die zweite Nachricht von Thread 1 .... dann die zweite Nachricht von Thread 2. -> Wenn ich nbAffichage bekomme = 2 für beide Threads ist das in Ordnung .... aber wenn der zweite nbAffichage = 4 ist ... funktioniert das nicht mehr. Ich verstehe warum ... aber ich sehe nicht, wie ich es beheben kann. – Minirock

+1

Ich denke, Ihre Tests geben Ihnen einen falschen Eindruck, dass die Variation in 'nbAffichage' das Hauptproblem ist. Die einfachste (wenn auch nicht sehr effiziente) Lösung ist eine Barriere, die alle Threads _N_ mal verbindet, auch wenn sie nur _n_ <_N_ mal drucken. –

+0

Ok, aber wie kann ich das machen? In der Tat ist dies nur eine einfache Übung, es gibt keine echte Anwendung, und ich denke, es wird einen besseren Weg geben, solche Dinge zu tun, als Mutex zu benutzen. Danke – Minirock