Как узнать, что вызывает сбой объекта futex?

Пытаюсь синхронизировать 5 процессов, они должны быть созданы от одного отца.

Я попытался вставить 5 идентификаторов ожидания, чтобы дождаться завершения дочернего процесса, но код никогда не достигает D4 и D5.

#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <sys/wait.h>


void func1(sem_t sem1, sem_t sem2);
void func2(sem_t sem1, sem_t sem2);
void func3(sem_t sem1, sem_t sem2);
void func4(sem_t sem1, sem_t sem2);
void func5(sem_t sem1, sem_t sem2);

int main() {
    sem_t s1;
    sem_t s2;

    sem_init(&s1, 1, -1);
    sem_init(&s2, 1, -1);

    void (*arr[5])(sem_t, sem_t) = {func1, func2, func3, func4, func5};

    int pid;

    for (int i=0; i<5; i++) {
        pid = fork();
        if (pid == 0) {
            arr[i](s1, s2);
            break;
        }
    }

    return 0;
}


void func1(sem_t sem1, sem_t sem2) {
    system("echo D1");
    sem_post(&sem1);
}

void func2(sem_t sem1, sem_t sem2) {
    system("echo D2");
    sem_post(&sem1);
}

void func3(sem_t sem1, sem_t sem2) {
    system("echo D3");
    sem_post(&sem2);
}

void func4(sem_t sem1, sem_t sem2) {
    sem_wait(&sem1);
    system("echo D4");
    sem_post(&sem2);
}

void func5(sem_t sem1, sem_t sem2) {
   sem_wait(&sem2);
    system("echo D5");
}

Я ожидаю, что D4 будет показан после D1 и D2, а D5 будет показан последним (D3 не зависит от D1, D2, D4). Но мой код никогда не достигает D4, потому что функция фьютекса возвращает непредвиденную ошибку.

Выход:

The futex facility returned an unexpected error code.D1
D2
D3

person AQUATH    schedule 26.12.2018    source источник
comment
1. int sem_init(sem_t *sem, int pshared, unsigned int value);, обратите внимание на unsigned. 2. передача sem_t по значению   -  person EOF    schedule 26.12.2018
comment
относительно таких утверждений, как: sem_init(&s1, 1, -1); третий параметр должен быть значением без знака. Вот синтаксис со страницы MAN: ` int sem_init(sem_t *sem, int pshared, unsigned int value);`   -  person user3629249    schedule 27.12.2018
comment
в функции: main(), перед оператором: return 0; должен быть цикл, который содержит: while( wait( NULL ) != -1){;} Чтобы родительский процесс не завершился до завершения всех дочерних процессов   -  person user3629249    schedule 27.12.2018


Ответы (2)


Вы передаете семафоры по значению, что неверно, поскольку переменная sem_t в каждой функции является копией оригинала. (Вот почему такие функции, как sem_init(), sem_post() и sem_wait(), принимают в качестве аргумента адреса семафора.)

Вам нужно передать семафоры по адресу, чтобы каждая функция работала с исходными семафорами:

void func1(sem_t *sem1, sem_t *sem2);
void func2(sem_t *sem1, sem_t *sem2);
void func3(sem_t *sem1, sem_t *sem2);
void func4(sem_t *sem1, sem_t *sem2);
void func5(sem_t *sem1, sem_t *sem2);

и

void (*arr[5])(sem_t *, sem_t *) = {func1, func2, func3, func4, func5};

И вызовите функцию как:

        arr[i](&s1, &s2);

Тогда функции должны иметь вид:

void func1(sem_t *sem1, sem_t *sem2) {
    system("echo D1");
    sem_post(sem1);
}

Обратите внимание, что адрес, переданный func1(), передается непосредственно sem_post().

Изменить:

Как уже отмечали другие, вы неправильно инициализируете семафоры. Вы не можете инициализировать семафор отрицательным значением.

Правильные общие семафоры

Как отмечено в комментариях, семфоры не находятся в памяти, совместно используемой несколькими процессами.

Один из способов поместить семфоры в разделяемую память — использовать mmap():

#include <sys/mman.h>

int main() {
    ...
    // map a 4k page of shared memory (assumes a sem_t is small
    // enough to fit at least two)
    void *sharedMem = mmap( 0, 4 * 1024, PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS, -1, 0 );

    // use the mmap()'d memory as shared semphores
    sem_t *semArray = ( sem_t * ) sharedMem;

    // initialize the semaphores
    sem_init( &( semArray[ 0 ] ), 1, 0 );
    sem_init( &( semArray[ 1 ] ), 1, 0 );

Код вызова становится

    arr[i](&( semArray[ 0 ] ), &( semArray[ 1 ] ));
person Andrew Henle    schedule 26.12.2018
comment
Спасибо, я понимаю свою ошибку, но, к сожалению, это не причина ошибки. Проблема возникает из-за того, что я инициализирую свои семафоры отрицательным значением. Я должен найти обходной путь для этого, так как я обязан использовать не более 2 семафоров. Редактировать для вашего редактирования: точно. - person AQUATH; 26.12.2018
comment
@AQUATH Передача по значению тоже проблема. Если вы передаете по значению, семафор, который функция ожидает или передает, может отличаться от семафора, используемого другим процессом. Он может работать в некоторых реализациях (например, если sem_t реализован как указатель на объект, определяемый реализацией), но на него нельзя рассчитывать. - person Andrew Henle; 26.12.2018
comment
@AndrewHenle Почти уверен, что передача по значению работает, потому что семафоры в любом случае являются поддельными, учитывая, что они не размещены в общей памяти. - person EOF; 26.12.2018
comment
@Эндрю Хенле Да, действительно. Я изменил инициализацию семафоров на 0 и добавил второй сигнал ожидания для func4 и func5, но они никогда не вызываются. - person AQUATH; 26.12.2018
comment
@EOF И это тоже. Я пропустил это, и это нужно было бы решить, чтобы создать полностью рабочий код. - person Andrew Henle; 26.12.2018
comment
Я сделал некоторую базовую отладку printf, проблема в том, что и func1, и func2 локально увеличивают s1 до 1, поэтому s1 никогда не равен 2, а D4 никогда не печатается. То же самое относится и к func5. - person AQUATH; 26.12.2018

Итак, в этот код нужно было внести 2 небольших изменения.

  1. Сначала вам нужно правильно инициализировать семафоры. sem_init(&s1, 1, 1); вместо sem_init(&s1, 1, -1);
  2. Ваш родительский процесс должен дождаться выхода всех дочерних процессов, прежде чем он сам завершится. Отсюда и wait(NULL); в main перед окончанием программы.

.

#include <unistd.h>
#include <semaphore.h>
#include <stdlib.h>
#include <sys/wait.h>


void func1(sem_t sem1, sem_t sem2);
void func2(sem_t sem1, sem_t sem2);
void func3(sem_t sem1, sem_t sem2);
void func4(sem_t sem1, sem_t sem2);
void func5(sem_t sem1, sem_t sem2);

int main() {
    sem_t s1;
    sem_t s2;

    sem_init(&s1, 1, 1);
    sem_init(&s2, 1, 1);

    void (*arr[5])(sem_t, sem_t) = {func1, func2, func3, func4, func5};

    pid_t child_pid, wpid;
    int status;

    for (int i=0; i<5; i++) {
        child_pid = fork();
        if (child_pid == 0) {
            arr[i](s1, s2);
            // break;
            exit(0);
        }
    }

    wait(NULL);
    // while ((wpid = wait(&status)) > 0);
    return 0;
}


void func1(sem_t sem1, sem_t sem2) {
    system("echo D1");
    sem_post(&sem1);
}

void func2(sem_t sem1, sem_t sem2) {
    system("echo D2");
    sem_post(&sem1);
}

void func3(sem_t sem1, sem_t sem2) {
    system("echo D3");
    sem_post(&sem2);
}

void func4(sem_t sem1, sem_t sem2) {
    sem_wait(&sem1);
    system("echo D4");
    sem_post(&sem2);
}

void func5(sem_t sem1, sem_t sem2) {
   sem_wait(&sem2);
    system("echo D5");
}

Вы можете запустить и проверить здесь. однострочный код

person Duck Dodgers    schedule 26.12.2018