void update_private(int pos, int start, int end, int index) {
     if(start == end && start == index) {
         return;
     }
     if(start > index || end < index) {
         return;
     }
     int middle = (start + end) / 2;
     int leftSon =(pos << 1);
     int rightSon = (pos << 1) + 1; 
     update_private(leftSon, start, middle, index);
     update_private(rightSon, middle + 1, end, index);
     int leftIndex = segment_tree_array[leftSon];
     int rightIndex = segment_tree_array[rightSon];
     if(array[leftIndex] <= array[rightIndex]) {
         segment_tree_array[pos] = leftIndex;
     }
     else {
         segment_tree_array[pos] = rightIndex;
     }
 }
Esempio n. 2
0
static void semwait(int sem)
{
    struct sembuf sbuf = { .sem_num = 0, .sem_op = -1, .sem_flg = 0 };
    assert (semop(sem, &sbuf, 1) != -1);
}

static void semsignal(int sem)
{
    struct sembuf sbuf = { .sem_num = 0, .sem_op = 1, .sem_flg = 0 };
    assert (semop(sem, &sbuf, 1) != -1);
}

static pid_t fork_generator(
    int sem_labyrinth, int shm_stats, int shm_labyrinth, int top_x, int top_y,
    int left_x, int left_y
)
{
    pid_t child = fork();
    if (child != 0) { // Parent
        assert (child != -1);
        return child;
    } else // Child
        exit(generator(
            sem_labyrinth, shm_stats, shm_labyrinth, top_x, top_y, 
            left_x, left_y)
        );
}

// Retourne la cellule qui partage le même mur.
static CELL *cell_fellow(CELL *cell, WALL orientation);

// Retourne l'orientation opposée d'un mur
static WALL orientation_inv(WALL orientation);

// Vérifie que certains murs privés ne partagent pas à présent les mêmes groupes
// ou qu'ils ne sont pas devenus partagés lorsque on a lié les deux groupes.
static void update_private(
    LABYRINTH labyrinth, CELL walls[], int *last_private, int *first_shared
);

static int generator(
    int sem_labyrinth, int shm_stats, int shm_labyrinth, int top_x, int top_y,
    int left_x, int left_y
)
{
    int size = LABYRINTH_SIZE / 2;

    // Récupère les mémoires partagées.
    PARAL_STATS *stats = (PARAL_STATS *) shmat(shm_stats, NULL, 0);
    assert (stats != (PARAL_STATS *) -1);
    LABYRINTH labyrinth = (LABYRINTH) shmat(shm_labyrinth, NULL, 0);
    assert (labyrinth != (LABYRINTH) -1);

    // Retiens les murs non ouverts dans la zone du générateur (indice de la
    // cellule avec orientation du mur, utilise les bits dédiés au groupe
    // pour encoder l'indice).
    // Ajoute les murs non partagés à partir de la gauche et ceux partagés à
    // partir de la droite du vecteur.
    int n_walls = 2 * size * size;
    int last_private = -1
      , first_shared = n_walls;
    CELL walls[n_walls];

    semwait(sem_labyrinth); // Accède en lecture à des cellules partagées.
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            int top_index  = (top_y + i)  * LABYRINTH_SIZE + top_x + j
              , left_index = (left_y + i) * LABYRINTH_SIZE + left_x + j;

            CELL *top_cell  = labyrinth + top_index
               , *left_cell = labyrinth + left_index;

            CELL top_fellow  = *cell_fellow(top_cell, WALL_TOP)
               , left_fellow = *cell_fellow(left_cell, WALL_LEFT);

            // Ajoute les murs sur des cases partagées à droite, les autres
            // à gauche.

            if (is_shared(*top_cell) && is_shared(top_fellow))
                walls[--first_shared] = WALL_TOP | (CELL) top_index;
            else
                walls[++last_private] = WALL_TOP | (CELL) top_index;

            if (is_shared(*left_cell) && is_shared(left_fellow))
                walls[--first_shared] = WALL_LEFT | (CELL) left_index;
            else
                walls[++last_private] = WALL_LEFT | (CELL) left_index;
        }
    }
    semsignal(sem_labyrinth);

    // Boucle tant qu'il reste des murs à supprimer.
    for (;;) {
        semwait(sem_labyrinth);

        // Vérifie que les murs partagés n'ont pas été supprimés par un autre
        // processus et qu'ils départagent toujours deux groupes différents.
        for (int i = n_walls - 1; i >= first_shared; i--) {
            CELL wall = walls[i];
            CELL index = wall & GROUP_MASK;
            WALL orientation = wall & WALLS_MASK;
            CELL *cell1 = labyrinth + index;
            CELL *cell2 = cell_fellow(cell1, orientation);

            bool can_be_removed =
                   is_wall(*cell1, orientation)
                && cell_root(labyrinth, cell1) != cell_root(labyrinth, cell2);

            if (!can_be_removed) // Ne peut plus supprimer ce mur.
                walls[i++] = walls[first_shared++];
        }

        // Sélectionne au hasard un mur dans les murs restants.
        int n_remaining = (last_private + 1) + (n_walls - first_shared);
        if (n_remaining == 0) {
            semsignal(sem_labyrinth);
            break;
        }
        int random_index = rand() % n_remaining;

        if (random_index <= last_private) {
            stats->hits++;
            semsignal(sem_labyrinth);

            // Cette partie de l'algorithme peut s'effectuer en même temps sur
            // différents processus :

            CELL wall = walls[random_index];
            CELL index = wall & GROUP_MASK;
            WALL orientation = wall & WALLS_MASK;
            CELL *cell1 = labyrinth + index;
            CELL *cell2 = cell_fellow(cell1, orientation);
            CELL *root1 = cell_root(labyrinth, cell1)
               , *root2 = cell_root(labyrinth, cell2);

            // Attache toujours une cellule qui n'appartient pas à un groupe
            // partagé à l'autre cellule. De cette manière, la racine d'un
            // groupe dont au moins une cellule est partagée sera une cellule
            // partagée. Ceci évite également de modifier une forêt qui pourrait
            // être modifiée par un autre processus au même moment.
            if (is_shared(*root1))
                cell_attach_group(root2, *root1);
            else
                cell_attach_group(root1, *root2);
            // Supprime le mur de la liste d'attente et des deux cellules.
            walls[random_index] = walls[last_private--];

            // Ces deux instructions sont équivalentes à ces deux instructions:
            // *cell1 &= ~orientation;
            // *cell2 &= ~orientation_inv(orientation);
            // A l'exception que le compilateur garantit que ces instructions
            // s'exécutent de manière atomique, et permet ainsi d'éviter que 
            // deux processus suppriment deux murs différents d'une même cellule
            // au même instant, ce qui engendrait une perte de l'une des deux
            // modifications.
            __sync_fetch_and_and(cell1, ~orientation);
            __sync_fetch_and_and(cell2, ~orientation_inv(orientation));
            // Une alternative aurait été d'acquérir la sémaphore sem_labyrinth
            // lorsque l'on change l'orientation d'une cellule qui est sur un
            // bord de la zone du générateur, mais cette méthode est
            // considérablement plus rapide.

            update_private(labyrinth, walls, &last_private, &first_shared);
        } else {
            stats->misses++;

            int wall_index = random_index - (last_private + 1) + first_shared;
            CELL wall = walls[wall_index];
            CELL index = wall & GROUP_MASK;
            WALL orientation = wall & WALLS_MASK;
            CELL *cell1 = labyrinth + index;
            CELL *cell2 = cell_fellow(cell1, orientation);
            CELL *root1 = cell_root(labyrinth, cell1);

            cell_attach_group(root1, *cell2);

            // Supprime le mur de la liste d'attente et des deux cellules.
            walls[wall_index] = walls[first_shared++];
            *cell1 &= ~orientation;
            *cell2 &= ~orientation_inv(orientation);

            semsignal(sem_labyrinth);
        }
    }
    return EXIT_SUCCESS;
}
 void update(int index, int value) {
     array[index] += value;
     update_private(1, 0, size - 1, index);
 }