1
votes

Synchronisation de processus en C sans attente occupée

J'implémente un serveur Web forking en C. L'idée de base est de créer plusieurs processus de travail à l'aide de l'appel système fork () et de les mettre en "veille" en attendant que le travail soit attribué par le processus parent. Le problème est que je ne peux pas utiliser l'attente occupée pour synchroniser les processus. J'ai besoin de quelques mécanismes comme pthread_cond_broadcast qui peuvent mettre les processus enfants en veille, de sorte que le processus parent puisse les réveiller si nécessaire.


1 commentaires

Vous pouvez établir un canal entre le parent et chaque enfant. L'enfant suspendra l'attente des données sur le tube. Le parent peut «réveiller» chaque enfant en envoyant un message sur le tube.


4 Réponses :


0
votes

Si vous devez utiliser fork () au lieu de pthreads , il existe des moyens de mapper la mémoire entre les processus sous UNIX en utilisant shm_open (voir aussi question similaire ) et mmap .

Je le ferais avec mmap comme ceci:

#include <stdio.h>
#include <unistd.h>

int main(){
  void *shared_mem=mmap(NULL,NUM_BYTES,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0);
  if(fork()){
    accessMem(shared_mem);
  }
  else{
    accessMem(shared_mem);
  }
}

Fondamentalement, l'idée est de marquer la région de la mémoire comme partagée entre les processus, puis après le fork, cette région de mémoire particulière reste constante entre les deux processus.

Bonne chance


1 commentaires

Le problème est que je ne peux pas utiliser de threads, je dois utiliser des fourches. Vous avez déjà essayé d'utiliser la mémoire partagée avec mmap comme vous l'avez dit, mais je n'arrive toujours pas à le faire fonctionner, une autre idée?



0
votes

Comme Jim Rogers l'a mentionné dans un commentaire , vous pouvez bloquer les processus enfants lors de la lecture d'un tube jusqu'à ce que vous ayez du travail à faire. Voici un exemple de la façon dont vous feriez cela avec un seul processus enfant:

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int childmain(int fd) {
    char c;
    if(read(fd, &c, 1) != 1) {
        perror("read");
        return 1;
    }
    printf("Hello from the child process! The parent just woke me up.\n");
    return 0;
}

int main(void) {
    int fds[2];
    if(pipe(fds)) {
        perror("pipe");
        return 1;
    }
    pid_t pid = fork();
    if(pid < 0) {
        perror("fork");
        return 1;
    } else if(pid == 0) {
        if(close(fds[1])) {
            perror("close");
            return 1;
        }
        return childmain(fds[0]);
    }
    if(close(fds[0])) {
        perror("close");
        goto out;
    }
    printf("Child is waiting. Hit Enter to wake it up.\n");
    getchar();
    if(write(fds[1], "", 1) != 1) {
        perror("write");
        goto out;
    }
    printf("Child sent wakeup signal. Now waiting for it to exit...\n");
  out:
    if(wait(NULL) != pid) {
        perror("wait");
        return 1;
    }
    return 0;
}


0 commentaires

0
votes

Il existe une variété de mécanismes de synchronisation que vous pouvez utiliser sur les systèmes POSIX (je suppose que vous avez POSIX comme vous avez fork)

  • des tubes (nommés ou non) peuvent être utilisés - écrire et lire des «jetons» pour synchroniser
  • Les objets sémaphore SYSV sont disponibles via sem_open - voir man sem_overview
  • sigwait et signaux peuvent être utilisés
  • Les
  • sockets (via socketpair ou connexion) peuvent être utilisés de la même manière que les tuyaux.

0 commentaires

0
votes

J'ai fini par utiliser les types de données conditionnelles et mutex pthread, j'ai dû les configurer comme des objets de partage (les créer sur la mémoire partagée et configurer leurs attributs). Exemple de code de l'initialisation.

Code pour initialiser pthread_mutexattr_t:

mut_allt = (pthread_mutex_t *) create_shared_memory(sizeof(pthread_mutex_t));
pthread_mutex_init(mut_allt, &mattr);

Cette fonction crée les attributs pour initialiser un verrou mutex comme PTHREAD_PROCESS_SHARED permettant plusieurs processus pour utiliser le verrou

Ensuite, utilisez cette fonction pour créer de la mémoire partagée:

void *create_shared_memory(size_t size) {
    int protection = PROT_READ | PROT_WRITE;
    int flags = MAP_SHARED | MAP_ANONYMOUS | MAP_SYNC;

    return mmap(NULL, size, protection, flags, -1, 0);
}

et initialiser le mutex:

pthread_mutexattr_t get_mutex_attributes() {
    pthread_mutexattr_t mattr;
    pthread_mutexattr_init(&mattr);
    // Attribute to allow the mutex to be shared between processes
    pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
    return mattr;
}

Avec tout cela et quelques mutex conditionnels, je parviens à synchroniser les processus, ce qui m'empêchait d'utiliser les conditions et mutex pthread auparavant était le fait que je ne les configurais pas correctement. J'espère que cela aide quelqu'un!


0 commentaires