Je dois faire un ordonnanceur en LIFO en C à l’aide de pthread.
L’ordonnanceur LIFO contient une seule pile de tâches dont la taille maximale est donnée par le
paramètre passé à sched_init. Initialement, la pile ne contient que la tâche initiale. Lorsqu’un
thread n’a rien à faire, il dépile une tâche de la pile et l’effectue; s’il n’y a aucune tâche prête,
le thread s’endort en attendant qu’il y en ait une (par exemple, la fonction sched_spawn peut
essayer de réveiller un thread). Lorsqu’une nouvelle tâche est créée, elle est empilée sur la pile.
L’ordonnanceur termine lorsque la pile est vide et tous les threads sont endormis.
Vous remarquerez que la pile est une structure partagée, il faudra donc la protéger par des pri-
mitives de synchronisation. Il faudra aussi utiliser des primitives de synchronisation pour réveiller
les threads endormis, et pour qu’ils terminent lorsque l’ordonnanceur devient oisif.
Voilà mon fichier.h
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
struct scheduler;
typedef void (*taskfunc)(void*, struct scheduler *);
// Structure pour une tâche
typedef struct {
taskfunc task;
void *closure;
} Task;
typedef struct scheduler
{
Task *tasks;
int qlen;
int nthreads;
int size;
pthread_t *threads;
pthread_mutex_t mutex; // Mutex pour la synchronisation
pthread_cond_t condition; // Condition pour attendre les tâches
} scheduler;
static inline int
sched_default_threads()
{
return sysconf(_SC_NPROCESSORS_ONLN);
}
int sched_init(int nthreads, int qlen, taskfunc f, void *closure);
int sched_spawn(taskfunc f, void *closure, struct scheduler *s);
#include "sched.h"
/*************************************************/
/* */
/* sucre syntaxique */
/* */
/*************************************************/
#define AND &&
#define OR ||
#define ISNOT !=
#define NOT !
#define then
typedef enum { FALSE, TRUE} bool;
/*************************************************/
/* */
/* predeclarations */
/* */
/*************************************************/
/* initialise un struct scheduler vide */
void initVide(struct scheduler *L);
/* renvoie 1 si le struct scheduler en parametre est vide, 0 sinon */
bool estVide(struct scheduler *L);
/* renvoie le premier element du struct scheduler en parametre */
taskfunc premier(struct scheduler *L);
/* renvoie un nouveau struct scheduler correspondant a celui en parametre, avec l'element task ajoute en haut de la pile */
struct scheduler ajoute(taskfunc task, void *closure, struct scheduler *L);
/* modifie le struct scheduler en parametre: task est ajoute comme premier element */
void empile(taskfunc task, void *closure, struct scheduler* L);
/* modifie le struct scheduler en parametre: le premier element est retire */
void depile(struct scheduler* L);
/* affichage simple du struct scheduler */
void affiche(struct scheduler *L);
/* longueur en recursif et en iteratif */
int longueur (struct scheduler *L);
/*************************************************/
/* */
/* briques de base */
/* */
/*************************************************/
void initVide(struct scheduler *L) {
L->tasks = NULL;
L->qlen = 0;
L->nthreads = 0;
L->size = 0;
L->threads = NULL;
pthread_mutex_init(&(L->mutex), NULL);
pthread_cond_init(&(L->condition), NULL);
}
bool estVide(struct scheduler *L) {
return L->size == 0;
}
taskfunc premier(struct scheduler *L) {
if (estVide(L)) {
fprintf(stderr, "Erreur : le struct scheduler est vide.n");
exit(EXIT_FAILURE);
}
return L->tasks[0].task;
}
struct scheduler ajoute(taskfunc task, void *closure, struct scheduler *L) {
Task newTask = {task, closure};
if (L->size >= L->qlen) {
fprintf(stderr, "Erreur : le scheduler est plein.n");
exit(EXIT_FAILURE);
}
L->tasks[L->size++] = newTask;
return *L;
}
void empile(taskfunc task, void *closure, struct scheduler *L)
{
ajoute(task, closure, L) ;
}
void depile(struct scheduler *L) {
if (estVide(L)) {
fprintf(stderr, "Erreur : le struct scheduler est vide.n");
exit(EXIT_FAILURE);
}
free(L->tasks[L->size - 1].closure); // Libère la mémoire de la tâche retirée
L->size--; // Réduit la taille du struct scheduler
}
/*************************************************/
/* */
/* Affiche, avec les briques de base */
/* */
/*************************************************/
void affiche(struct scheduler *L) {
for (int i = 0; i < L->size; i++) {
printf("%p ", L->tasks[i].task);
}
printf("n");
}
/*************************************************/
/* */
/* Longueur, sans les briques de base */
/* */
/*************************************************/
int longueur (struct scheduler *L)
{
return L -> size;
}
/*************************************************/
/* */
/* Libere la memoire */
/* */
/*************************************************/
void VideScheduler(struct scheduler *L)
{
if(NOT(estVide(L)))
{
depile(L);
VideScheduler(L);
}
}
// Fonction de tâche simple qui affiche un message
void *task_function(void *arg) {
char *message = (char *)arg;
printf("Thread %lu executing task: %sn", pthread_self(), message);
sleep(1); // Simulation d'une tâche longue
return NULL;
}
int sched_init(int nthreads, int qlen, taskfunc f, void *closure) {
// Faut initialiser notre ordonnanceur et créez les threads si nécessaire
// Il faut également initialiser la pile de tâches avec la tâche initiale
struct scheduler *scheduler = (struct scheduler *)malloc(sizeof(struct scheduler));
if (scheduler == NULL) {
perror("Erreur lors de l'allocation du struct scheduler");
return -1;
}
scheduler->nthreads = (nthreads == 0) ? sched_default_threads() : nthreads;
scheduler->qlen = qlen;
scheduler->tasks = (Task *)malloc(qlen * sizeof(Task));
if (scheduler->tasks == NULL) {
perror("Erreur lors de l'allocation de la mémoire pour les tâches");
free(scheduler);
return -1;
}
// Ajout de la tâche initiale au tableau de tâches
scheduler->tasks[0].task = f;
scheduler->tasks[0].closure = closure;
scheduler->size++;
// Vérification si la taille du tableau est suffisante pour le nombre de threads à créer
if (scheduler->nthreads > qlen) {
printf("Ajustement du nombre de threads au maximum de la capacité du tableau de tâches.n");
scheduler->nthreads = qlen;
}
// Création des threads
scheduler->threads = (pthread_t *)malloc(scheduler->nthreads * sizeof(pthread_t));
if (scheduler->threads == NULL) {
perror("Erreur lors de l'allocation de la mémoire pour les threads");
free(scheduler->tasks);
free(scheduler);
return -1;
}
for (int i = 0; i < scheduler->nthreads; i++) {
pthread_create(&(scheduler->threads[i]), NULL,(void *(*)(void *))f, closure);
}
// Ajout de la tâche initiale
empile(f, closure, scheduler);
// Attente de la fin des threads
for (int i = 1; i < scheduler->nthreads; i++) {
pthread_join(scheduler->threads[i], NULL);
}
return 0;
}
int sched_spawn(taskfunc f, void *closure, struct scheduler *s) {
return -1;
}
int main(){
char *message = "Task1";
// Initialisation du scheduler avec 2 threads et une longueur de file de 5
int result = sched_init(0, 4, task_function, (void*) message); // Initialisation du scheduler
if (result != 0) {
fprintf(stderr, "Erreur lors de l'initialisation du schedulern");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
J’ai essayé de faire ça pour un premier test mais j’ai l’impression que je suis hors-sujet. Pouvez-vous me dire si je suis bien en accord avec ce que j’ai expliqué dans l’énoncé svp ?
Je précise que j’ai un fichier annexe implémentant le quicksort et qui me sert d’exemple où je dois utiliser mon ordonnanceur LIFO afin qu’il exécute le quicksort et voir combien de temps il a mis pour faire ce quicksort.
VanDamme M1x VanM1x is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.