Можно ли форк / exec и гарантировать, что один запускается раньше другого? - PullRequest
6 голосов
/ 31 августа 2011

В значительной степени, как говорится в названии. У меня есть фрагмент кода, который выглядит следующим образом:

pid_t = p;

p = fork();

if (p == 0) {
    childfn();
} else if (p > 0) {
    parentfn();
} else {
    // error
}

Я хочу убедиться, что родитель или дочерний элемент выполняет (но не возвращает из) свои соответствующие функции раньше других.

Что-то вроде вызова sleep (), вероятно, будет работать, но не гарантируется никаким стандартом, и будет просто использовать детали реализации планировщика ОС ... это возможно? Будет ли работать vfork?

edit: Обе функции переходят к вызову system (), одна из которых не вернется, пока не будет запущена другая. Итак, для повторения: мне нужно убедиться, что родитель или потомок только вызывают свои соответствующие функции (но не возвращают, потому что они не будут, что и предлагают все решения на основе мьютекса ниже) перед другим. Есть идеи? Извините за отсутствие ясности.

edit2: Имея один вызов процесса sched_yield и sleep, я, похоже, получаю довольно надежные результаты. vfork обеспечивает семантику, которую я ищу, но имеет слишком много ограничений на то, что я могу сделать в дочернем процессе (я могу в значительной степени только вызвать exec). Итак, я нашел несколько обходных путей, которые достаточно хороши, но не имеют реального решения. vfork, вероятно, ближе всего к тому, что я искал, но все представленные ниже решения будут работать более или менее.

Ответы [ 5 ]

5 голосов
/ 01 сентября 2011

Мьютекс должен быть в состоянии решить эту проблему.Заблокируйте мьютекс перед вызовом fork и сделайте, чтобы 1-я функция выполнялась как обычно, в то время как вторая пытается получить мьютекс.1-й должен разблокировать мьютекс, когда он будет сделан, а второй будет ждать, пока он освободится.

РЕДАКТИРОВАТЬ: Mutex должен находиться в сегменте общей памяти для двух процессов

5 голосов
/ 01 сентября 2011

Эта проблема обычно решается с помощью мьютекса или семафора . Например:

// Get a page of shared memory
int pagesize = getpagesize();
void *mem = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if(!mem)
{
  perror("mmap");
  return 1;
}

// Put the semaphore at the start of the shared page.  The rest of the page
// is unused.
sem_t *sem = mem;
sem_init(sem, 1, 1);

pid_t p = fork();

if (p == 0) {
    sem_wait(sem);
    childfn();
    sem_post(sem);
} else if (p > 0) {
    sem_wait(sem);
    parentfn();
    sem_post(sem);

    int status;
    wait(&status);
    sem_destroy(sem);
} else {
    // error
}

// Clean up
munmap(mem, pagesize);

Вы также можете использовать мьютекс в области совместно используемой памяти, но вам необходимо убедиться, что вы создали атрибуты, отличные от заданных по умолчанию, с атрибутом process-shared, который называется shared (через pthread_mutexattr_setpshared(&mutex, PTHREAD_PROCESS_SHARED)) в чтобы он работал.

Это гарантирует, что только один из childfn или parentfn будет выполняться в любой момент времени, но они могут работать в любом порядке. Если вам нужно сначала запустить конкретный прогон, запустите семафор со счетчика 1 вместо 0, и у вас должна быть функция, которая должна запускаться в первую очередь, не дожидаясь семафора (но все же отправьте сообщение в него, когда закончите). Вы также можете использовать условную переменную , которая имеет другую семантику.

3 голосов
/ 01 сентября 2011

Самый безопасный способ - использовать (именованный) канал или сокет. Одна сторона пишет в нее, другая читает. Читатель не может прочитать то, что еще не было написано.

1 голос
/ 01 сентября 2011

Используйте семфор, чтобы убедиться, что один запускается раньше другого.

0 голосов
/ 31 августа 2011

Вы можете использовать атомарную переменную.Установите его в ноль до того, как вы выполните fork / thread / exec, первый процесс установит его в единицу непосредственно перед (или, что еще лучше, после), когда он войдет в функцию, а второй будет ждать пока (flag == 0).

...