Ожидание на нескольких семафорах или нескольких очередях сообщений - PullRequest
0 голосов
/ 11 декабря 2018

В большинстве реализаций UNIX процессы могут блокировать более одного события.То есть, вместо того, чтобы ожидать один семафор или получать из одной очереди сообщений, процесс может ожидать несколько семафоров или нескольких очередей сообщений.Какое преимущество дает такая возможность?Как бы вы это реализовали?

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

Мои мысли по этому поводу - что-то вроде этого:

typedef struct QueueElement {
    int Sender;
    int Receiver;
    char Message[MAX_MSG_SIZE];
    int MessageSize;
} QueueElement;

QueueElement MessageQueue[NUM_OF_PROCESSES];



/* Send Message to receiving process queue number */
int SendMsg(int SenderId, int ReceiverId, char* Msg, int Size)
{
    /* Create Queue Element to Enqueue */
    QueueElement El = {
        .Sender = SenderId,
        .Receiver = ...
        .
        .
    };

    /* Enqueue element in queue specified by Receiver's Id */
    Enqueue(&(MessageQueue[ReceiverId]), El);
}



/* Get messages for process defined by ReceiverId, from any queue */
int RecvMsg(int* SenderId, int ReceiverId, char* Msg, int* size)
{
    int i;
    for (i=NUM_OF_PROCESSES; i>=0; i--)
    {
        /* If a message is available for receiving process, Dequeue element from queue */
        if (MessageQueue[i].Receiver = ReceiverId)
        {
            QueueElement El = Dequeue(&(MessageQueue[i]));
            *SenderId = El.Sender;
            strcpy(Msg, El.Message);
            .
            .
            .

            return TRUE;
        }
    }

    return FALSE;
}

Теперь рассмотрим 4 процесса, выполняющихся параллельно.Они отправляют сообщения в очереди сообщений 1, 2, 3, 4 непрерывно.Теперь предположим, что все сообщения отправляются процессу 2. Это означает, что процесс 2 должен проверять сообщения во всех 4 очередях (1, 2, 3, 4).Но если новые сообщения добавляются непрерывно, обрабатываются только сообщения в очереди 4.Как справиться с голодом других очередей сообщений?

Есть ли лучший способ справиться с этим?Как современные архитектуры справляются с этим?Проблема этого решения заключается в том, что если сообщения продолжают помещаться в очередь в очередь с высоким приоритетом (NUM_OF_PROCESSES), сообщения в очередях с более низким приоритетом никогда не будут обрабатываться.

Ответы [ 3 ]

0 голосов
/ 11 декабря 2018

Я не думаю, что ваш код отвечает на вопрос так, как намеревается задать вопрос.Чтобы расширить суть вопроса:

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

  • Какой тип API вам нужен?Показать функцию или набор функций, которые позволили бы кому-либо читать из нескольких источников одновременно.

Подсказка: select () делает именно это.Хорошие ключевые слова для Google включают "выбрать", "мультиплексирование" и "неблокирующий ввод / вывод".

0 голосов
/ 11 декабря 2018

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

0 голосов
/ 11 декабря 2018

Есть ли лучший способ справиться с этим?

Да.Основная проблема заключается в том, что ваш код постоянно тратит впустую опрос процессора, потому что он вообще не ждет.

Лучший способ - поместить его в ядро, например:

  • когда задача вызывает RecvMsg(), ядро ​​может выполнить if no messages in queue { tell scheduler this task should block until a message is received } атомарно (без условий гонки)

  • когда что-либо вызывает SendMsg(), ядро ​​может сделать if receiving task is blocked waiting for a message { tell scheduler the receiving task should be unblocked }атомарно (без условий гонки)

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

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

  • реализовать все поверх сообщений, чтобы вам приходилось только ждать сообщения.

Длявторое решение;в основном вы заменяете традиционное процедурное программирование моделью актера.

...