IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

FreeRTOS et variable persistante


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut FreeRTOS et variable persistante
    Bonjour,

    C'est la première fois que j’utilise un OS (FreeRTOS) sur un µControleur et j'aimerai être certain de ne pas faire de boulettes sur la gestion des variables persistantes partagées entre plusieurs threads.

    Mon application : j'ai un équipement qui est configurable via plusieurs processus (HTTP, Telnet, FTP, console série, ...). Une variable persistante contient la configuration active du produit.

    Pour la modification de la configuration, je pensais mettre en place un système avec de mutex. Lorsque des commandes de configurations sont reçues par l'équipement, le processus actif :
    - réserve le mutex
    - copie dans une variable temporaire persistante la configuration active
    - traite les commandes reçues en modifiant la variable temporaire
    - si pas d'erreur détecté pendant le traitement (on a validé que toutes les commandes reçues étaient valide) : copie la configuration de la variable temporaire vers la variable de la configuration active
    - libère le mutex
    => Le traitement dure entre 100 et 1000ms (ex: traitement fichier de configuration par FTP) s'il n'y a pas de problème de communication Ethernet (et donc beaucoup plus en cas de perte de paquets Ethernet).

    Pour l'affichage de la configuration active par l'un des processus, je pense faire comme ça :
    - réserve le mutex
    - affiche les informations contenues dans la variable configuration active
    - libère le mutex
    => Le traitement peut dure entre 50 et 300ms s'il n'y a pas de problème de communication Ethernet

    Remarque : il n'y qu'une variable temporaire pour tous les processus. Cela permet d'éviter de devoir créer une variable temporaire pour chaque socket de chaque processus, ce qui permet de limiter la consommation de la RAM (la variable configuration active fait environ 25% de la RAM disponible).
    Remarque : le traitement de modification de la configuration peut donc bloquer les traitement d'affichage de la configuration.


    Est-ce que vous pensez que c'est la bonne méthode ?
    Merci d'avance

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Après réflexion, avec mon système on ne peut pas avoir plusieurs processus d'affichage qui puissent lire la variable configuration active en même temps ce qui est un peu dommage.

    N'y aurait pas un moyen de mettre en place ces règles :
    - un processus en mode écriture se met en idle à la prise du semaphore s'il y a déjà un autre processus en train de lire ou d'écrire dans la variable configuration active
    - un processus en mode lecture se met en idle à la prise du semaphore s'il y a déjà un autre processus en train d'écrire dans la variable configuration active
    => avec ce système on pourrait donc avoir plusieurs processus de lecture en même temps tant qu'il n'y a pas de processus d'écriture actif.
    => je ne vois pas comment faire car il n'existe pas une fonction à ma connaissance qui permette de prendre tous les jetons de la semaphore et à la seule condition qu'aucun jeton ne soit pris (sinon le processus doit passer en idle)

  3. #3
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Le système que tu proposes a un nom : il s'agit du problème des lecteurs et des écrivains (à tout instant on a au maximum un seul écrivain ou un nombre quelconque de lecteurs) sur lequel tu trouveras certainement de la littérature.
    Mais on réserve ce traitement à des actions très courtes (moins de 0.1ms) pour des durées de plusieurs millisecondes ça n'est pas approprié d'attendre 1000ms qu'une donnée devienne accessible!

    Une méthode rapide utilise un système de multi-buffering, par exemple s'il n'existe qu'un écrivain :
    On utilise un tableau de 2 structures de données. La donnée accessible en lecture est indiquée par un pointeur, l'autre est accessible en écriture (donc les deux actions peuvent être simultanés!)
    Quand une écriture est terminée, il y a conflit écrivain/lecteurs. L'écrivain ferme l'accès aux lecteurs, attend que tous les éventuels lecteurs soient sortis, échange les 2 pointeurs, pour enfin libérer l'entrée des lecteurs. A cet instant les lecteurs ont accès à la nouvelle zone, et l'écrivain peut "tranquillement" remplir les nouvelles données dans l'autre zone.

  4. #4
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    4 493
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 493
    Billets dans le blog
    1
    Par défaut
    Pourquoi locker le mutex avant de tout récupérer ? Il serait peut-être mieux de récupérer les données, tout valider, locker le mutex, faire une simple copie de structure, déverrouiller le mutex. Ainsi, le temps de prise du mutex est très bref. Idem pour lire : tu lockes, tu copies, tu délockes, tu affiches.

    EDIT : mince je viens de voir ta remarque....

    EDIT 2 : la variable de configuration fait 25 % de la RAM mais tu as un OS, une stack IP et du HTTP... Quelle taille fait cette variable ?

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Merci, le système de multi-buffering me semble convenir.

    La variable de configuration fait 65Ko (sur 512Ko disponible). Sachant qu'il faut faire x2 pour le second buffer (d'où les 25% environ... je pense que je dos pouvoir un peu compresser ma structure actuelle).
    Aussi, je comptais créer un troisième buffer pour avoir la dernière configuration enregistrée afin de pouvoir afficher indicateur "configuration non enregistrée" (si contenu variable configuration active différent de variable configuration enregistrée, alors flag = 1)... mais il va très certainement que je trouve un autre système car ça commence à faire beaucoup de RAM à réserver.

  6. #6
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    Citation Envoyé par boboss123 Voir le message
    N'y aurait pas un moyen de mettre en place ces règles :
    - un processus en mode écriture se met en idle à la prise du semaphore s'il y a déjà un autre processus en train de lire ou d'écrire dans la variable configuration active
    - un processus en mode lecture se met en idle à la prise du semaphore s'il y a déjà un autre processus en train d'écrire dans la variable configuration active
    => avec ce système on pourrait donc avoir plusieurs processus de lecture en même temps tant qu'il n'y a pas de processus d'écriture actif.
    => je ne vois pas comment faire car il n'existe pas une fonction à ma connaissance qui permette de prendre tous les jetons de la semaphore et à la seule condition qu'aucun jeton ne soit pris (sinon le processus doit passer en idle)
    Tu ne peux pas t'en tirer avec une seule primitive de synchronisation. Je dirais qu'il en faut au moins trois, même s'il n'y a qu'un seul écrivain. Cela dépend aussi du fait qu'il soit possible ou non pour un processus de modifier l'état d'une primitive qu'il n'a pas lui-même verrouillé. Des solutions sont évoquées sur la page Wikipédia dédiée.

  7. #7
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    Merci Matt, je me suis inspiré du second exemple pour gérer mon cas :

    Par contre, j'ai quand même quelques doutes que mon code ne soit pas bloquant sous certaines conditions : ça vous semble bon ?

    Gestion des semaphores :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
     
    // Il y a deux buffers
    // - Le premier buffer contient la configuration active de l'équipement : elle ne doit être accessible qu'en lecture seule pour le code application
    // - Le second buffer est une zone de travail temporaire : lorsque l'équipement reçoit une nouvelle demande de configuration, la configuration active est copiée dans ce buffer puis le processus modifie la zone de travail en fonction des commandes reçues.
    // => une fois toutes les commandes reçues sont traitées, la nouvelle configuration est appliquée au hardware de l'équipement puis le buffer de travail temporaire devient la configuration active.
    //
    // Un seul processus à la fois est autorisé à travailler sur la zone de travail temporaire.
    // Plusieurs processus à la fois sont autorisé à lire la configuration active sauf au moment où le switch entre les deux buffers est effectué.
    // Le switch entre les deux buffers n'est autorisé que s'il n'y a plus aucun processus qui travaille sur la configuration active.
    // 
    // writerReadersProcess_ptrRead : pointeur sur la structure en lecture seul (configuration active)
    // writerReadersProcess_ptrWrite : pointeur sur la seconde structure qui est en lecture et écriture (configuration temporaire)
    // writerReadersProcess_readersCounter : nombre de reader en cours
    SemaphoreHandle_t mutex_writer; // pour la réservation du writer actif (un seul à la fois)
    SemaphoreHandle_t mutex_changePersistentInfos; // modification des variables persistantes en cours (writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite et writerReadersProcess_readersCounter)
    SemaphoreHandle_t mutex_blockNewReader; // pour empecher un nouveau reader d'être autorisé pendant la mise à jour des pointeurs writerReadersProcess_ptrRead et writerReadersProcess_ptrWrite
     
     
    STRUCT_CONFIG config1;
    STRUCT_CONFIG config2;
    STRUCT_CONFIG * writerReadersProcess_ptrRead;
    STRUCT_CONFIG * writerReadersProcess_ptrWrite;
    int writerReadersProcess_readersCounter;
     
     
    void writerReadersProcess_init(void){
    	mutex_changePersistentInfos = xSemaphoreCreateMutex();
    	if(mutex_changePersistentInfos == NULL){
    		printf("[ERR] mutex_changePersistentInfos init\r\n");
    		while(1);
    	}
     
    	mutex_writer = xSemaphoreCreateMutex();
    	if(mutex_writer == NULL){
    		printf("[ERR] mutex_writer init\r\n");
    		while(1);
    	}	
     
    	mutex_blockNewReader = xSemaphoreCreateMutex();
    	if(mutex_blockNewReader == NULL){
    		printf("[ERR] mutex_blockNewReader init\r\n");
    		while(1);
    	}	
     
    	writerReadersProcess_ptrRead = &config1;
    	writerReadersProcess_ptrWrite = &config2;
     
    	writerReadersProcess_readersCounter = 0;
    }
     
     
    // Réserve le mutex du processus de lecture
    // => On peut ouvrir autant de readers que l'on veut sauf si le writer en en train de modifier
    //    les pointeurs writerReadersProcess_ptrRead et writerReadersProcess_ptrWrite.
    const STRUCT_CONFIG * writerReadersProcess_openReader(void){
    	STRUCT_CONFIG * ret;
     
    	xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    	if(writerReadersProcess_readersCounter == 0){
    		xSemaphoreTake(mutex_blockNewReader, portMAX_DELAY); // réservation du mutex pour indiquer qu'il y a au moins un reader d'actif
    	}
    	writerReadersProcess_readersCounter++;
    	ret = writerReadersProcess_ptrRead;
    	xSemaphoreGive(mutex_changePersistentInfos);
     
    	return ret;
    }
     
     
    void writerReadersProcess_closeReader(void){
    	xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    	writerReadersProcess_readersCounter--;
    	if(writerReadersProcess_readersCounter == 0){
    		xSemaphoreGive(mutex_blockNewReader); // libération du mutex pour indiquer qu'il n'y a plus aucun reader d'actif
    	}
    	xSemaphoreGive(mutex_changePersistentInfos);
    }
     
     
     
    // Réserve le mutex du processus d'écriture
    // Copie structure de la configuration en mode lecture vers structure de la configuration en mode ecriture
    // => On peut réserver un writer alors qu'il y a déja des readers d'actifs car le writer n'écrit pas dans la même zone mémoire que les readers lisent
    STRUCT_CONFIG * writerReadersProcess_openWriter(void){
    	xSemaphoreTake(mutex_writer, portMAX_DELAY);  // Réservation du mutex du processus d'écriture
    	memcpy(writerReadersProcess_ptrWrite, writerReadersProcess_ptrRead, sizeof(STRUCT_CONFIG)); // Le CPU tourne à 330DMIPS (65Ko à copier)
    	return writerReadersProcess_ptrWrite;
    }
     
     
     
     
    // Libère le mutex du processus d'écriture
    // Si enableNewConfig vaut TRUE, échange les adresses pointées
    // par les pointeurs de lecture et d'écriture (la zone de travail en écriture, devient la zone de lecture)
    // => le changement des pointeurs ne se fait que s'il y a aucun reader d'ouvert
    void writerReadersProcess_closeWriter(BOOL enableNewConfig){
    	SemaphoreHandle_t ptrTmp;
     
    	if(enableNewConfig){
    		xSemaphoreTake(mutex_blockNewReader, portMAX_DELAY); // pour empecher qu'un nouveau reader soit ouvert pendant le switch de writerReadersProcess_ptrRead et writerReadersProcess_ptrWrite
    		xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
     
    		// Mise à jour de la configuration active
    		ptrTmp = writerReadersProcess_ptrRead;
    		writerReadersProcess_ptrRead = writerReadersProcess_ptrWrite;
    		writerReadersProcess_ptrWrite = ptrTmp;
     
    		xSemaphoreGive(mutex_changePersistentInfos);
    		xSemaphoreGive(mutex_blockNewReader); // autorise un nouveau reader a être réservé
    	}
     
     
    	xSemaphoreGive(mutex_writer); // Libération du mutex du processus d'écriture
    }
    Exemple code application :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    void HTTP_requestCallBack(void){
     
    	if(HTTP_isPostCommand()){ // traitement HTTP POST
     
    		BOOL enableNewConfig = TRUE;
    		STRUCT_CONFIG * ptrWrite = writerReadersProcess_openWriter();
     
    		// ****************************
    		// Traitement des commandes reçues
    		if(HTTP_processPost(ptrWrite) == FALSE){
    			enableNewConfig = FALSE; // Erreur détectée dans le traitement des commandes reçues
    		}
    		// *********************
     
    		if(enableNewConfig){
    			applyConfigToHardware(ptrWrite); // Application de la nouvelle configuration au hardware
    		}
     
    		// ****************************
    		HTTP_SendStatus(enableNewConfig); // renvoie une page web indicant si le traitement s'est bien déroulé
    		// ****************************
     
    		writerReadersProcess_closeWriter(enableNewConfig);
     
    	} else { // traitement HTTP GET
    		const STRUCT_CONFIG * ptrRead = writerReadersProcess_openReader();
     
    		HTTP_SendProductConfig(ptrRead);  // renvoie une page web contenant la configuration de l'équipement
     
    		writerReadersProcess_closeReader();
    	}
    }

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    ... mon système ne marche pas, je peux me retrouver dans des cas bloquants.

    Dans writerReadersProcess_closeWriter(), si le processus est interrompu juste après xSemaphoreTake(mutex_blockNewReader, portMAX_DELAY), si writerReadersProcess_openReader() est appelé, les deux fonctions s'inter-bloquent si writerReadersProcess_counter vaut 0.

  9. #9
    Membre chevronné
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    1 855
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 1 855
    Par défaut
    J'ai modifié mon gestionnaire de semaphore :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
     
    // Il y a deux buffers
    // - Le premier buffer contient la configuration active de l'équipement : elle ne doit être accessible qu'en lecture seule pour le code application
    // - Le second buffer est une zone de travail temporaire : lorsque l'équipement reçoit une nouvelle demande de configuration (appel de writerReadersProcess_openWriter()),
    //   la configuration active est copiée dans ce buffer puis le processus applicatif doit modifier la zone de travail en fonction des commandes de configuration reçues.
    // => une fois toutes les commandes reçues sont traitées, la nouvelle configuration doit être appliquée au hardware de l'équipement puis les données de la zone de travail
    //    sont copiées dans la configuration active en appelant writerReadersProcess_closeWriter(TRUE).
    //
    // Un seul processus à la fois est autorisé à travailler sur la zone de travail temporaire (writerReadersProcess_openWriter() est blocant dans qu'il y a un writer d'actif).
    // Plusieurs processus à la fois sont autorisés à lire la configuration active sauf au moment de la mise à jour de celle-ci.
    // La mise à jour de la configuration active n'est autorisé que s'il n'y a plus aucun processus de lecture qui travaille sur la configuration active.
    //
    // La gestion des semaphore est inspirée de : https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem#Second_readers-writers_problem
    // 
    // writerReadersProcess_ptrRead : pointeur sur la structure en lecture seul (configuration active)
    // writerReadersProcess_ptrWrite : pointeur sur la seconde structure qui est en lecture et écriture (configuration temporaire)
    // writerReadersProcess_readersCounter : nombre de reader en cours
    // writerReadersProcess_writersCounter : nombre de writer en cours
    SemaphoreHandle_t mutex_changePersistentInfos; // accès pour modification des variables persistantes (writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite et writerReadersProcess_readersCounter, writerReadersProcess_writersCounter)
     
    STRUCT_CONFIG config1;
    STRUCT_CONFIG config2;
    STRUCT_CONFIG * writerReadersProcess_ptrRead;
    STRUCT_CONFIG * writerReadersProcess_ptrWrite;
    int writerReadersProcess_readersCounter;
    int writerReadersProcess_writersCounter;
     
    void writerReadersProcess_init(void){
    	mutex_changePersistentInfos = xSemaphoreCreateMutex();
    	if(mutex_changePersistentInfos == NULL){
    		printf("[ERR] mutex_changePersistentInfos init\r\n");
    		while(1);
    	}
     
    	writerReadersProcess_ptrRead = &config1;
    	writerReadersProcess_ptrWrite = &config2;
     
    	writerReadersProcess_readersCounter = 0;
    	writerReadersProcess_writersCounter = 0;
    }
     
     
    // Réserve le mutex du processus de lecture
    // => On peut ouvrir autant de readers que l'on veut sauf pendant que les 
    //    données de writerReadersProcess_ptrWrite sont copiées dans writerReadersProcess_ptrRead.
    const STRUCT_CONFIG * writerReadersProcess_openReader(void){
    	STRUCT_CONFIG * ret;
     
    	while(1){
    		xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    		if(writerReadersProcess_writersCounter == 0){ // il n'y a plus/pas de writer actif
    			break; // pour pouvoir sortir de la boucle
     
    		}
    		xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
    	}
     
    	writerReadersProcess_readersCounter++;
    	ret = writerReadersProcess_ptrRead;
    	xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
     
    	return ret;
    }
     
     
    void writerReadersProcess_closeReader(void){
    	xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    	writerReadersProcess_readersCounter--;
    	xSemaphoreGive(mutex_changePersistentInfos);
    }
     
     
     
    // Réserve le mutex du processus d'écriture
    // Copie structure des données de writerReadersProcess_ptrRead dans writerReadersProcess_ptrWrite
    // => On peut réserver un writer alors qu'il y a déja des readers d'actifs car le writer n'écrit pas dans la même zone mémoire que les readers
    STRUCT_CONFIG * writerReadersProcess_openWriter(void){
    	while(1){
    		xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    		if(writerReadersProcess_writersCounter == 0){ // il n'y a plus/pas de writer actif
    			break; // pour pouvoir sortir de la boucle
     
    		}
    		xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
    	}
     
    	// Initialisation du buffer de travail 
    	memcpy(writerReadersProcess_ptrWrite, writerReadersProcess_ptrRead, sizeof(*writerReadersProcess_ptrWrite)); // 65Ko à copier avec CPU 330DMIPS	
     
    	writerReadersProcess_writersCounter++;	
    	xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
     
    	return writerReadersProcess_ptrWrite;
    }
     
     
     
     
    // Libère le mutex du processus d'écriture
    // Si enableNewConfig vaut TRUE, mise à jour de writerReadersProcess_ptrRead avec valeurs de writerReadersProcess_ptrWrite
    // => le changement ne se fait que s'il y a aucun reader d'ouvert
    void writerReadersProcess_closeWriter(BOOL enableNewConfig){
     
    	if(enableNewConfig){
    		while(1){
    			xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    			if(writerReadersProcess_readersCounter == 0){ // il n'y a plus/pas de reader actif
    				break; // pour pouvoir sortir de la boucle
     
    			}
    			xSemaphoreGive(mutex_changePersistentInfos); // redonne la main aux autres processus pour pouvoir libérer les readers actifs
    		}
     
    		// Mise à jour de la configuration active avec les nouvelles données du buffer de travail
    		memcpy(writerReadersProcess_ptrRead, writerReadersProcess_ptrWrite, sizeof(*writerReadersProcess_ptrRead));	// 65Ko à copier avec CPU 330DMIPS
     
    		xSemaphoreGive(mutex_changePersistentInfos); // autorise un nouveau reader a être réservé
     
    	}
     
    	xSemaphoreTake(mutex_changePersistentInfos, portMAX_DELAY);
    	writerReadersProcess_writersCounter--; // Mise à jour du nombre de Writer
    	xSemaphoreGive(mutex_changePersistentInfos);
    }
    Je pense que cette fois ça fonctionne mais est-ce que le système ne pourrait pas être plus élégant/performant (je ne suis pas fan des boucles while(1)) ?

    PS : à la fermeture du writer, j'ai décidé de remplacer la permutation de pointeur par une copie des deux buffers pour faciliter la migration de mes anciens programmes vers FreeRTOS (car sinon, il faut que je modifie toutes mes fonctions de configuration car elles travaillaient toutes directement sur le buffer temporaire (il n'y avait pas d'utilisation de pointeur pour travailler sur la structure)). Je ne pense pas que ça soit très gênant pour les performances du système (à confirmer).

Discussions similaires

  1. Réponses: 4
    Dernier message: 06/06/2018, 21h14
  2. Variable persistante (bash, sed)
    Par fransoo dans le forum Shell et commandes GNU
    Réponses: 12
    Dernier message: 19/02/2017, 21h53
  3. Variables persistantes dans la page
    Par Champouil dans le forum ASP.NET
    Réponses: 13
    Dernier message: 16/03/2013, 13h19
  4. Variable persistante dans un partialLoop() ?
    Par Samsawell dans le forum Zend Framework
    Réponses: 0
    Dernier message: 04/04/2011, 11h18
  5. [Dates] Variable persistante à arrêter!
    Par godjojo dans le forum Langage
    Réponses: 7
    Dernier message: 20/05/2007, 19h12

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo