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

Embarqué Discussion :

[FreeRTOS] Comment gérer un event qui peut être généré par plusieurs taches ?


Sujet :

Embarqué

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 726
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 726
    Points : 873
    Points
    873
    Par défaut [FreeRTOS] Comment gérer un event qui peut être généré par plusieurs taches ?
    Bonjour,

    Je me pose une question : lorsque l'on a une tache qui est en attente d'un évènement et que cet évènement peut être généré par plusieurs taches, comment gère t-on ce cas ?
    ... car si on utilise un simple sémaphore, je ne vois pas comment gérer le cas où plusieurs évènements sont générés pendant que la tache réceptrice est en train de traiter l'event courant.

    Un exemple ?

    Merci d'avance

  2. #2
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    février 2011
    Messages
    5 526
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : février 2011
    Messages : 5 526
    Points : 16 521
    Points
    16 521
    Par défaut
    Salut Boboss123.

    Citation Envoyé par Boboss123
    Je me pose une question : lorsque l'on a une tache qui est en attente d'un évènement et que cet évènement peut être généré par plusieurs taches, comment gère t-on ce cas ?
    Je ne comprends pas le sens de votre question.
    La tâche reste en attente d'une exécution tant qu'il n'y a aucun évènement à l'horizon. Dès qu'un nouvel évènement arrive, votre tâche s'exécute. S'il existe plusieurs évènements qui se déclenche en même temps alors vous aurez plusieurs tâche qui vont s'exécuter, une tâche par évènement.

    Citation Envoyé par Boboss123
    ... car si on utilise un simple sémaphore, je ne vois pas comment gérer le cas où plusieurs évènements sont générés pendant que la tache réceptrice est en train de traiter l'event courant.
    Il faut comprendre que votre tâche peut s'exécuter en parallèle mais pas entièrement car il existe des parties de votre code qui peuvent créer des conflits d'accès, comme par exemple une écriture. Pour résoudre cela, on utilise un MUTEX qui permet de bloquer la partie qui pose problème en la rendant unique à l'exécution, même si d'autre tâche sont en cours d'exécution à ce moment là. C'est comme si vous aviez une fil d'attente à l'exécution. Le premier arrivé est le premier servit et ainsi de suite.

    Cordialement.
    Arteus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 726
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 726
    Points : 873
    Points
    873
    Par défaut
    Bonjour,

    Voici un exemple, ça sera peut-être plus clair :
    Code c : 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
     
    #include "FreeRTOS.h"
    #define TASK_STACK_SIZE	(configMINIMAL_STACK_SIZE + 1000)
     
    typedef struct {
    	const char * taskname;
    	int val;
    	SemaphoreHandle_t mutex;
    	SemaphoreHandle_t event;
    } STRUCT_DATA;
    static STRUCT_DATA local_data;
     
     
    void sendTask(void *param){
    	STRUCT_DATA * data = (STRUCT_DATA*)param;
    	while(1){		
    		xSemaphoreTake(data->mutex, portMAX_DELAY);
    			TaskStatus_t xTaskDetails;
    			vTaskGetInfo(NULL, &xTaskDetails, pdFALSE, eInvalid);		
    			data->taskname = xTaskDetails.pcTaskName;
    			data->val++;
    		xSemaphoreGive(data->mutex);
     
    		// Send Event
    		xSemaphoreGive(data->event);
    	}
    }
     
     
    void receiveTask(void *param){
    	STRUCT_DATA * data = (STRUCT_DATA*)param;
    	while(1){
    		// Wait Event
    		xSemaphoreTake(data->event, portMAX_DELAY);
     
    		xSemaphoreTake(data->mutex, portMAX_DELAY);		
    			printf("[Task %s] val %i\r\n", data->taskname, data->val);
    		xSemaphoreGive(data->mutex);
    	}
    }
     
    void app_init(void){
    	local_data.mutex = xSemaphoreCreateMutex();
    	local_data.event = xSemaphoreCreateBinary();
     
    	xTaskCreate((TaskFunction_t) &receiveTask, 	"receiveTask", 	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask,		"task1",	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task2", 	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task3", 	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
     
    }
     
    void main(void){
    	app_init();
    	vTaskStartScheduler();
    }


    ça m'affiche :
    [Task task3] val 15817981
    [Task task3] val 15819450 // ... on a sauté des events (15817981 => 15819450)
    [Task task3] val 15819450
    [Task task3] val 15819880
    [Task task3] val 15819880 // ... event dupliqué (même valeur que précédemment)
    [Task task3] val 15820454
    [Task task3] val 15820454
    [Task task3] val 15821924
    [Task task3] val 15821924
    [Task task3] val 15823838
    [Task task3] val 15823838
    [Task task3] val 15824865
    [Task task3] val 15824865
    [Task task3] val 15825872
    [Task task3] val 15825872
    [Task task3] val 15826899
    [Task task3] val 15826899
    [Task task3] val 15828408
    [Task task3] val 15828408
    [Task task3] val 15828990
    [Task task3] val 15828990
    ... on voit que l'on rate des évènements et que certains sont dupliqués.

  4. #4
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 726
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 726
    Points : 873
    Points
    873
    Par défaut
    J'ai peut-être trouvé une solution mais ça demande d'utiliser un semaphore en plus :
    Code c : 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
     
    #include "FreeRTOS.h"
    #define TASK_STACK_SIZE	(configMINIMAL_STACK_SIZE + 1000)
     
    typedef struct {
    	int taskId;
    	int val;
    	SemaphoreHandle_t mutex;
    	SemaphoreHandle_t txEvent;
    	SemaphoreHandle_t rxEvent;
    } STRUCT_DATA;
    static STRUCT_DATA local_data;
     
    typedef struct {
    	int taskId;
    	STRUCT_DATA * data;	
    } STRUCT_TASK_INFO;
     
     
    void sendTask(void *param){
    	STRUCT_TASK_INFO * context = (STRUCT_TASK_INFO*)param;
    	STRUCT_DATA * data = (STRUCT_DATA*)context->data;
    	while(1){
    		// Wait Event
    		xSemaphoreTake(data->rxEvent, portMAX_DELAY);
     
    		xSemaphoreTake(data->mutex, portMAX_DELAY);
    			data->taskId = context->taskId;
    			data->val++;
    		xSemaphoreGive(data->mutex);
     
    		// Send Event
    		xSemaphoreGive(data->txEvent);
    	}
    }
     
     
    void receiveTask(void *param){
    	STRUCT_DATA * data = (STRUCT_DATA*)param;
     
        // Send Event : task is ready
        xSemaphoreGive(data->rxEvent);
     
    	while(1){
    		// Wait Event
    		xSemaphoreTake(data->txEvent, portMAX_DELAY);
     
    		xSemaphoreTake(data->mutex, portMAX_DELAY);		
    			printf("[Task task%i] val %i\r\n", data->taskId, data->val);
    		xSemaphoreGive(data->mutex);
     
    		// Send Event
    		xSemaphoreGive(data->rxEvent);
    	}
    }
     
    void app_init(void){
    	local_data.mutex = xSemaphoreCreateMutex();
    	local_data.txEvent = xSemaphoreCreateBinary();
    	local_data.rxEvent = xSemaphoreCreateBinary();
     
    	static STRUCT_TASK_INFO task1Context;
    		task1Context.data = &local_data;
    		task1Context.taskId = 1;
    	static STRUCT_TASK_INFO task2Context;
    		task2Context.data = &local_data;
    		task2Context.taskId = 2;
    	static STRUCT_TASK_INFO task3Context;
    		task3Context.data = &local_data;
    		task3Context.taskId = 3;
     
    	xTaskCreate((TaskFunction_t) &receiveTask, 	"receiveTask", 	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask,		"task1",        TASK_STACK_SIZE, &task1Context, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task2",        TASK_STACK_SIZE, &task2Context, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task3",        TASK_STACK_SIZE, &task3Context, tskIDLE_PRIORITY+1, NULL);
     
    }
     
    void main(void){
    	app_init();
    	vTaskStartScheduler();
    }

    ... C'est certain que ça fonctionne ?
    ... On est obligé d'utiliser un mutex en plus ?

    EDIT : je ne suis pas certain mais a priori, en augmentant le niveau de priorité de la tache receiveTask(), le code fonctionne sans le semaphore rxEvent : tous les events sont affichés et pas de duplication d'évènements

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 726
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 726
    Points : 873
    Points
    873
    Par défaut
    CAS n°2
    Je suis en train de tester un second cas d'école :
    J'ai trois taches qui peuvent générer un même event.
    Chacune des 3 taches met un flag à 1 (chaque tache met sont propre flag à 1 : tache0 met le flag0 à 1, ... , tache2 met le flag2 à 1).
    Une 4ième tache (tache qui écoute l'event) attend que l'event soit levé et affiche les flags actifs avant de les remettre à 0.
    Si la 4ième tache n'a pas traité l'event, les trois premières taches n'ont pas besoin de régénérer l'event mais elles mettent quand même leur flag à 1 s'il n'est pas déja actif et elles continuent leur exécution normalement (elles n'attendent pas que la 4ième tache est terminée le traitement).

    Code c : 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
    125
     
    #include "FreeRTOS.h"
    #define TASK_STACK_SIZE	(configMINIMAL_STACK_SIZE + 1000)
    //#define USE_RX_ENVENT // permet de synchroniser les taches TX et RX
    #define IGNORE_DUPPLICATE_EVENT // permet d'ignorer les évènements suppliqués (data->flags == 0)
    typedef struct {
    	int taskId;
    	int val; // compteur pour debug
    	unsigned int flags;
    	SemaphoreHandle_t mutex;
    	SemaphoreHandle_t txEvent;
    #ifdef USE_RX_ENVENT
    	SemaphoreHandle_t rxEvent;
    #endif // USE_RX_ENVENT
    } STRUCT_DATA;
    static STRUCT_DATA local_data;
     
    typedef struct {
    	int taskId;
    	STRUCT_DATA * data;	
    } STRUCT_TASK_INFO;
     
     
    void sendTask(void *param){
    	STRUCT_TASK_INFO * context = (STRUCT_TASK_INFO*)param;
    	STRUCT_DATA * data = (STRUCT_DATA*)context->data;
    	while(1){
                #ifdef USE_RX_ENVENT
                    // Wait Event
                    xSemaphoreTake(data->rxEvent, portMAX_DELAY);
                #endif //  USE_RX_ENVENT
     
                int flagIsSet;
                xSemaphoreTake(data->mutex, portMAX_DELAY);
                    data->taskId = context->taskId;
                    data->val++;
     
                    unsigned int bitmask = 1 << context->taskId;
                    if(data->flags & bitmask){
                       // Le précédent event n'a pas encore été traité par receiveTask()
                       // => pas besoin de renvoyer l'event
                       flagIsSet = 0;
                    } else {
                       data->flags |= bitmask;
                       flagIsSet = 1;
                    }
                xSemaphoreGive(data->mutex);
     
                if(flagIsSet){
                    // Send Event
                    xSemaphoreGive(data->txEvent);
                }
    	}
    }
     
     
    void receiveTask(void *param){
    	STRUCT_DATA * data = (STRUCT_DATA*)param;
     
        #ifdef USE_RX_ENVENT
            // Send Event : task is ready
            xSemaphoreGive(data->rxEvent);
    	#endif //  USE_RX_ENVENT
     
    	while(1){
    		// Wait Event
    		xSemaphoreTake(data->txEvent, portMAX_DELAY);
     
    		xSemaphoreTake(data->mutex, portMAX_DELAY);
            #ifdef IGNORE_DUPPLICATE_EVENT
            if(data->flags){
            #endif // IGNORE_DUPPLICATE_EVENT
                int flag0 = (data->flags & 0x01 ? 1 : 0);
                int flag1 = (data->flags & 0x02 ? 1 : 0);
                int flag2 = (data->flags & 0x04 ? 1 : 0);
     
                printf("[Task task%i] val %i, flag0:%i, flag1:%i, flag2:%i [flags count %i]\r\n",
                    data->taskId, data->val,
                    flag0, flag1, flag2,
                    flag0+flag1+flag2
                );
                if(data->flags == 0){
                    printf(" => [DUPPLICATE EVENT] flags = 0\r\n");
                }
                data->flags = 0; // clear flags
            #ifdef IGNORE_DUPPLICATE_EVENT
            }
            #endif // IGNORE_DUPPLICATE_EVENT
    		xSemaphoreGive(data->mutex);
     
            #ifdef USE_RX_ENVENT
                // Send Event
                xSemaphoreGive(data->rxEvent);
            #endif //  USE_RX_ENVENT
    	}
    }
     
    void app_init(void){
    	local_data.mutex = xSemaphoreCreateMutex();
    	local_data.txEvent = xSemaphoreCreateBinary();
        #ifdef USE_RX_ENVENT
            local_data.rxEvent = xSemaphoreCreateBinary();
        #endif // USE_RX_ENVENT
     
    	static STRUCT_TASK_INFO task1Context;
    		task1Context.data = &local_data;
    		task1Context.taskId = 0;
    	static STRUCT_TASK_INFO task2Context;
    		task2Context.data = &local_data;
    		task2Context.taskId = 1;
    	static STRUCT_TASK_INFO task3Context;
    		task3Context.data = &local_data;
    		task3Context.taskId = 2;
     
    	xTaskCreate((TaskFunction_t) &receiveTask, 	"receiveTask", 	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask,		"task0",        TASK_STACK_SIZE, &task1Context, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task1",        TASK_STACK_SIZE, &task2Context, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task2",        TASK_STACK_SIZE, &task3Context, tskIDLE_PRIORITY+1, NULL);
     
    }
     
    void main(void){
    	app_init();
    	vTaskStartScheduler();
    }

    ... mon code fonctionne presque correctement : le problème est que parfois, data->flags vaut 0 dans alors que l'event receiveTask()... la fonction prend donc du temps CPU pour ne rien faire car elle n'a rien à traiter. Comment faire pour éviter cela ?

  6. #6
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    février 2011
    Messages
    5 526
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : février 2011
    Messages : 5 526
    Points : 16 521
    Points
    16 521
    Par défaut
    Salut Boboss123.

    Votre exemple n'est pas parlant car je ne sais pas ce qu'il faut voir.

    Citation Envoyé par Boboss123
    J'ai trois taches qui peuvent générer un même event.
    La première question est de savoir combien vous avez de files à l'exécution dans votre processeur.
    J'ai un ordinateur qui possède quatre cœurs et donc huit files d'attentes (ou thread).
    Afin de ne pas me retrouver dans ce que l'on nomme un deadlock (un verrou mortel), le nombre des tâches père mise en attente sera au maximum de sept.
    Ainsi la tâche fils aura la huitième position et pourra toujours s'exécuter sans être mise en attente, ce qui provoquerait le deadlock.

    Qu'est-ce qu'une tâche père ? C'est la tâche qui va transmettre les données à la tâche fils.
    Pour ce faire, à chaque tâche père, je gère un sémaphore qui lui est personnel.
    De cette façon, je sérialise la file N°x à une tâche à la fois, mais comme je l'ai dit, je gère sept file en parallèle.
    De cette façon, quand je lance une nouvelle tâche père, je sais que l'ancienne est terminée.

    Par simplification, je numérote mes tâches père et c'est ce numéro que je vais transmettre à la tâche fils.

    Pour sérialiser, j'utilise donc un sémaphore qui est propre à la tâche.
    Tant que la tâche n'est pas terminé, il ne libère pas son occupation dans la file d'attente et nous ne pouvons pas introduire une nouvelle tâche.
    Ainsi dans la tâche qui se termine, je peux lancer une nouvelle tâche qui va se mettre en attente pus libérer le sémaphore.

    Le goulot d'étranglement est le nombre de files à l'exécution. Dans mon exemple, j'ai huit treads, et donc sept tâches père, que j'ai numéro de 1 à 7 et une tâche fils.

    Pour gérer les données, j'utilise un tableau numéroté de 1 à 7.
    Il n'est pas nécessaire de mettre un MUTEX car il n'y a aucun conflit d'accès.
    A la limite, vous pouvez en mettre un pour l'affichage afin de ne pas avoir le texte mélangé avec une autre tâche.

    Pourquoi gérer la file d'attente ?
    Il m'est arrivé d'avoir des milliers de tâches en attente, de provoquer un débordement et de planter l'ordinateur.

    Il faut comprendre que le MUTEX est nécessaire si vous avez des conflits d'accès.
    Le cas le plus classique est l'écriture dans un disque ou encore à l'affichage pour éviter de mélanger le texte avec une autre tâche.

    La gestion du MUTEX se fait d'elle même. Il suffit de créer un MUTEX pour que celui-ci sache s'il doit se mettre en attente que la ressource se libère ou bloquer le traitement jusqu'à sa libération.

    Citation Envoyé par Boboss123
    Comment faire pour éviter cela ?
    Je ne connais pas FreeRTos. J'ai fait cela sous windows.
    Il existe des fonctions de mise en attente (wait) qui permettent de gérer la fin des processus ou des thread.
    --> WaitForSingleObject() : pour la sérialisation d'une tâche.
    --> WaitForMultipleObjects() : pour le nombre de tâches que l'on peut avoir en parallèle.

    Il faut regarder la documentation.

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 726
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 726
    Points : 873
    Points
    873
    Par défaut
    Bonjour,

    Citation Envoyé par Artemus24 Voir le message
    Votre exemple n'est pas parlant car je ne sais pas ce qu'il faut voir.
    Je vais me concentrer sur le premier cas évoqué pour éviter de partir dans tous les sens. J'ai trois taches père et une tache fils : lorsqu'une tache père envoie une info à la tache fils, la tache fils doit traiter cette information une seule fois. La tache fils doit-être reveillée par l'OS uniquement lorsqu'il y a une information à traiter.


    Citation Envoyé par Artemus24 Voir le message
    La première question est de savoir combien vous avez de files à l'exécution dans votre processeur.
    C'est un processeur avec un seul coeur, je ne vois pas le soucis de traiter plusieurs taches : c'est le rôle de l'OS de pouvoir faire ça il me semble.


    Citation Envoyé par Artemus24 Voir le message
    Je ne connais pas FreeRTos. J'ai fait cela sous windows.
    Il existe des fonctions de mise en attente (wait) qui permettent de gérer la fin des processus ou des thread.
    --> WaitForSingleObject() : pour la sérialisation d'une tâche.
    --> WaitForMultipleObjects() : pour le nombre de tâches que l'on peut avoir en parallèle.
    A priori, on doit pouvoir utiliser ce système pour avoir le même comportement que WaitForSingleObject() : https://www.freertos.org/Pend-on-mul...s-objects.html
    ... je vais tester

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    septembre 2009
    Messages
    1 726
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : septembre 2009
    Messages : 1 726
    Points : 873
    Points
    873
    Par défaut
    ça a l'air de fonctionner avec le système de queue pour le premier cas (je n'ai plus besoin de mutex/semaphore... uniquement une seule queue) :
    Code c : 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
     
    #include "FreeRTOS.h"
    #define TASK_STACK_SIZE	(configMINIMAL_STACK_SIZE + 1000)
     
    typedef enum {
    	ENUM_EVENT_TYPE__TASK1,
    	ENUM_EVENT_TYPE__TASK2,
    	ENUM_EVENT_TYPE__TASK3	
    } ENUM_EVENT_TYPE;
     
    typedef struct {
        ENUM_EVENT_TYPE eventType;
        int val;
    } STRUCT_QUEUE_OBJ;
     
    typedef struct {
        ENUM_EVENT_TYPE taskId;
        QueueHandle_t queue;
    } STRUCT_DATA;
    static STRUCT_DATA local_data;
     
    typedef struct {
        ENUM_EVENT_TYPE taskId;
        STRUCT_DATA * data;
    } STRUCT_TASK;
     
     
    void sendTask(void *param){
    	STRUCT_TASK * context = (STRUCT_TASK*)param;
        STRUCT_DATA * data = (STRUCT_DATA*)context->data;
        int val = 10000*context->taskId; // offset suivant la tache (permet de pouvoir vérifier que la valeur affichée correspond bien à la tache indiquée)
    	while(1){
            STRUCT_QUEUE_OBJ obj;
            obj.eventType = context->taskId;
            obj.val = val++;
            xQueueSend(data->queue, &obj, portMAX_DELAY);
    	}
    }
     
     
    void receiveTask(void *param){
    	STRUCT_DATA * data = (STRUCT_DATA*)param;
    	while(1){
    		// Wait Event
            STRUCT_QUEUE_OBJ obj;
    		xQueueReceive(data->queue, &obj, portMAX_DELAY);
     
            printf("[Task %i] val %05i\r\n", obj.eventType, obj.val);
    	}
    }
     
    void app_init(void){
    	local_data.queue = xQueueCreate(1, sizeof(STRUCT_QUEUE_OBJ));
        static STRUCT_TASK context1 = {.taskId = ENUM_EVENT_TYPE__TASK1, .data = &local_data};
        static STRUCT_TASK context2 = {.taskId = ENUM_EVENT_TYPE__TASK2, .data = &local_data};
        static STRUCT_TASK context3 = {.taskId = ENUM_EVENT_TYPE__TASK3, .data = &local_data};
     
    	xTaskCreate((TaskFunction_t) &receiveTask, 	"receiveTask", 	TASK_STACK_SIZE, &local_data, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask,		"task1",	TASK_STACK_SIZE, &context1, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task2", 	TASK_STACK_SIZE, &context2, tskIDLE_PRIORITY+1, NULL);
    	xTaskCreate((TaskFunction_t) &sendTask, 	"task3", 	TASK_STACK_SIZE, &context3, tskIDLE_PRIORITY+1, NULL);
    }
     
    void main(void){
    	app_init();
    	vTaskStartScheduler();
    }

    ... par contre, le système de queue ne semble pas être adapté au "cas n°2" que je voudrais traiter : il me semble impossible pour les thread père de générer des events non-blocants sans perdre d'évènement ou sans avoir une duplication d'évènement sur le thread fils.

  9. #9
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    février 2011
    Messages
    5 526
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : février 2011
    Messages : 5 526
    Points : 16 521
    Points
    16 521
    Par défaut
    Salut Boboss123.

    Citation Envoyé par Boboss
    C'est un processeur avec un seul cœur, je ne vois pas le soucis de traiter plusieurs taches : c'est le rôle de l'OS de pouvoir faire ça il me semble.
    Un processeur est constitué par plusieurs cœurs et chaque cœur possède plusieurs threads que l'on nomme aussi une fil d'exécution. Une tâche va s'exécuter dans une fil d'exécution. Cela te permet d'exécuter en parallèle plusieurs tâches et donc de gagner du temps à l'exécution.

    Il existe une autre technique que l'on nomme slicing, qui correspond à découper chaque processus en tranche de temps identique.
    Même si en apparence, tu as l'impression de faire du parallèle, il y a en fait une sérialisation qui est faite. A l'exécution le slicing met plus de temps que le multicœurs.

    Il doit exister des didacticiels pour le multithreading dans le FreeRTos. Tu devrais t'en inspirer. C'est ce que j'ai fait avec Microsoft.

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

Discussions similaires

  1. Réponses: 6
    Dernier message: 06/10/2019, 10h43
  2. [XL-2003] Comment documenter un DTPickers avec le contenu d'une cellule qui peut être vide.
    Par MichaSarah dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 05/12/2010, 00h54
  3. Réponses: 4
    Dernier message: 11/08/2010, 16h01
  4. Comment insérer une date qui peut être nulle ?
    Par guidav dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 30/01/2007, 16h18
  5. [...] doit utiliser une requête qui peut être mise à jour
    Par requiemforadream dans le forum ASP
    Réponses: 4
    Dernier message: 26/04/2005, 09h12

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