Программа C Reader Writer, одна программа чтения не читает все данные

Я работаю над программой чтения/записи, в которой есть один писатель для n читателей. У меня возникла проблема, из-за которой, если подключено несколько читателей, как показано на скриншоте ниже, то все сообщение из общей памяти не отображается.

Вывод:

Введите сообщение: Тест

Читатель1: тест

Читатель2: тест

Писатель: тест тест

Читатель1: тест

Reader2: тестовый тест

Писатель:

введите здесь описание изображения

Читатели:

введите здесь описание изображения

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

Любые предложения о том, как заставить читателей печатать, будь то флаг или какой-то подсчет? Ниже также приложены скриншоты циклов записи и чтения.

Читатель:

int main() {
    DataShared data;
    data.turn = 0;
    signal(SIGINT, sigHandler);

    //generates key
    key = ftok("mkey",65);

    //returns an identifier in mId
    if ((mId = shmget(key, SIZE, IPC_CREAT|S_IRUSR|S_IWUSR)) < 0){
    perror("shared memory error");
    exit(1);
    }

    // shmat to attach to shared memory
    if((mPtr = shmat(mId, 0, 0)) == (void*) -1) {
    perror("Can't attach\n");
    exit(1);
    }


    while(1) {
        // request critical section
        while(!data.turn && data.count == 0) {
        //not time for the reader, check if token is changed.
            memcpy(&data, mPtr, sizeof(DataShared));
        }

        data.count++;

        // enter critical section
        usleep(1);
        fprintf(stderr, "Read from memory: %s\n", data.message);
        usleep(1);
        // leave critical section

        data.count--;

        while(data.count > 0){
            ;
        }

        data.turn = 0;
        memcpy(mPtr, &data, sizeof(DataShared));
    };

    return 0;
}

Писатель:

int main() {
    DataShared data;
    data.turn = 0;
    data.count = 0;
    signal(SIGINT, sigHandler);

    key = ftok("mkey",65);

    if((shmId = shmget(key, SIZE, IPC_CREAT|S_IRUSR|S_IWUSR)) < 0 ) {
        perror("Error creating shared memory\n");
        exit(1);
    }

    if((shmPtr = shmat(shmId, 0, 0)) == (void*) -1) {
        perror("Can't attach\n");
        exit(1);
    }

    while(1) {
        while (data.turn) {
            memcpy(&data, shmPtr, sizeof(DataShared));
        }

        // enter critical section
        printf("Enter a message: \n" );
        fgets(data.message, 1024, stdin);


        // leave critical section
        printf("Message written to memory: %s\n", data.message);
        data.turn = 1;
        memcpy(shmPtr, &data, sizeof(DataShared));
    };

    return 0;
}

person Striker    schedule 03.10.2019    source источник
comment
Пожалуйста, удалите изображения и замените их текстом.   -  person Ed Heal    schedule 03.10.2019
comment
@ 500-InternalServerError Я пытаюсь сделать это без семафоров или потоков.   -  person Striker    schedule 03.10.2019
comment
@PaulOgilvie Разве это никогда не изменит поворот от писателя к читателю, потому что флаг никогда не будет сохранен в общей памяти?   -  person Striker    schedule 03.10.2019
comment
Я не понимаю здесь расписания.   -  person Paul Ogilvie    schedule 03.10.2019
comment
@PaulOgilvie Писатель отправляет сообщение в общую память, затем оно потребляется n читателями, затем они сообщают писателю, что его очередь писать снова. Повторить.   -  person Striker    schedule 03.10.2019
comment
Кто устанавливает контроль над читателем (читателями) и кто устанавливает контроль над писателем? Все они находятся в бесконечном цикле. Есть несколько потоков?   -  person Paul Ogilvie    schedule 03.10.2019
comment
@PaulOgilvie находится в бесконечном цикле, пока не будет вызвано прерывание с использованием ctrl-c, в котором вызывается shmctl, и программа завершается.   -  person Striker    schedule 03.10.2019
comment
Пожалуйста, покажите нам свою главную, где вы начинаете читатели и писатели.   -  person Paul Ogilvie    schedule 03.10.2019
comment
@PaulOgilvie добавил   -  person Striker    schedule 03.10.2019


Ответы (1)


Это не может быть объяснением вашего наблюдения, но то, что вы делаете, подозрительно.

У вас есть несколько процессов, и ОС планирует каждый процесс.

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

Тогда ваш data.count. Он начинается с локальной переменной data модуля записи. там вы не инициализируете data.count, поэтому оно имеет неопределенное значение. В ридерах вы устанавливаете его на 0, но он будет перезаписан значением из общей памяти (неопределенное значение). Вы делаете ++, позже -- и затем ждете, пока он не станет 0. Как это может стать нулем? Этот читатель мог ждать вечно.

person Paul Ogilvie    schedule 03.10.2019
comment
Первая проблема, на которую вы указали, - это причина, по которой я добавил счет, это было сделано для того, чтобы я проверил, чтобы убедиться, что все читатели печатают, прежде чем писатель сможет снова начать. Проблема с переменной count в текущем способе ее реализации также известна, и я снова протестировал ее инициализацию в Writer, но безуспешно. Эта проблема определенно становится лучше меня :) - person Striker; 03.10.2019
comment
Я не вижу, чтобы вы инициализировали data.count в модуле записи. - person Paul Ogilvie; 03.10.2019
comment
Обновлен вопрос, где data.count инициализируется в писателе. - person Striker; 03.10.2019
comment
ХОРОШО. После data.count++; не следует ли скопировать его обратно в общую память? Иначе его никто не увидит. И это может вызвать другие проблемы с синхронизацией.... - person Paul Ogilvie; 03.10.2019
comment
Гарантирует ли memcpy в общей памяти атомарность? - person Paul Ogilvie; 03.10.2019
comment
Я попытался записать его обратно в общую память после data.count++, но это закончилось тем, что один из читателей попал в цикл занятости и никогда не вернулся. а что ответить на ваш второй вопрос я честно не знаю - person Striker; 03.10.2019
comment
@Striker Если вы просматриваете всю memcpy() документацию, которую можете найти, видите ли вы хоть какое-нибудь упоминание о том, что копия является атомарной? - person Andrew Henle; 03.10.2019
comment
@AndrewHenle Я вижу, что упоминается, что он не атомарный - person Striker; 03.10.2019