Синхронизация процессов в C без занятого ожидания - PullRequest
1 голос
/ 26 апреля 2020

Я реализую разветвленный веб-сервер в C. Основная идея c заключается в создании нескольких рабочих процессов с использованием системного вызова fork() и переводе их в «спящий режим» в ожидании выполнения работы родительским процессом. Проблема в том, что я не могу использовать занятое ожидание для синхронизации процессов. Мне нужны некоторые механизмы, такие как pthread_cond_broadcast, которые могут усыпить дочерние процессы, чтобы родительский процесс мог их разбудить по мере необходимости.

Ответы [ 4 ]

0 голосов
/ 28 апреля 2020

В итоге я использовал условные и мьютексные типы данных pthread, мне пришлось настроить их как общие объекты (создать их в общей памяти и настроить их атрибуты). Пример кода инициализации.

Код для инициализации pthread_mutexattr_t:

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;
}

Эта функция создает атрибуты для инициализации блокировки мьютекса как PTHREAD_PROCESS_SHARED, позволяя нескольким процессам использовать блокировку

Затем используйте эту функцию для создания общей памяти:

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);
}

и инициализации мьютекса:

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

Со всем этим и некоторыми условными мьютексами мне удается синхронизировать процессы то, что мешало мне использовать условные выражения pthread и мьютекс, было то, что я не настраивал их должным образом. Надеюсь, это кому-нибудь поможет!

0 голосов
/ 26 апреля 2020

Как и Джим Роджерс, упомянутый в комментарии , вы можете блокировать дочерние процессы при чтении канала, пока у вас не будет работы для них. Вот пример того, как вы могли бы сделать это с одним дочерним процессом:

#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 голосов
/ 26 апреля 2020

Существует множество механизмов синхронизации, которые вы можете использовать в системах POSIX (я предполагаю, что у вас есть POSIX, поскольку у вас есть fork)

  • каналы (именованные или безымянные) могут использоваться - писать и читать «токены» для синхронизации
  • Объекты семафора SYSV доступны через sem_open - см. man sem_overview
  • sigwait и сигналы могут использоваться
  • сокеты (через сокет или соединение) могут использоваться аналогично трубам.
0 голосов
/ 26 апреля 2020

Если вам нужно использовать fork() вместо pthreads, есть способы сопоставить память между процессами в UNIX, используя shm_open (см. Также аналогичный вопрос ) и mmap .

Я бы сделал это с mmap следующим образом:

#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);
  }
}

По сути, идея состоит в том, что вы помечаете область памяти как общую для процессов, а затем после вилка, эта конкретная область памяти остается постоянной между двумя процессами.

Удачи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...