Ожидание, пока другой процесс не заблокирует, а затем разблокирует мьютекс Win32

0

Я пытаюсь сказать, когда процесс производителя обращается к общему обоюдному файлу mutex. После этого мне нужно заблокировать тот же мьютекс и обработать связанные данные. Есть ли способ в Windows, чтобы сделать это, за исключением смешной циклы?

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

То, что, как я считаю, будет работать (нелепо неэффективно), будет таким (ПРИМЕЧАНИЕ: это не мой реальный код, я знаю, что в этом есть 10 разных вещей, я хочу, чтобы этого не делалось):

#include <Windows.h>

int main() {
    HANDLE h = CreateMutex(NULL, 0, "name");
    if(!h) return -1;

    int locked = 0;
    while(true) {
        if(locked) {
            //can assume it wont be locked longer than a second, but even if it does should work fine
            if(WaitForSingleObject(h, 1000) == WAIT_OBJECT_0) {
                // do processing...
                locked = 0;
                ReleaseMutex(h);
            }
        // oh god this is ugly, and wastes so much CPU...
        } else if(!(locked = WaitForSingleObject(h, 0) == WAIT_TIMEOUT)) {
            ReleaseMutex(h);
        }
    }
    return 0;
}

Если по какой-либо причине с C++ существует более простой способ, мой код на самом деле. Этот пример был просто проще построить в C.

  • 0
    Также используйте событие ( CreateEvent ), и производитель может установить его, чтобы ваш другой процесс знал, что пора обрабатывать данные.
  • 0
    На самом деле, в зависимости от того, как написан продюсер, ваш код может зайти в тупик.
Показать ещё 8 комментариев
Теги:
winapi
ipc

2 ответа

2

Вы не сможете избежать изменения производителя, если необходим эффективный обмен. Для этого ваш дизайн имеет фундаментальные недостатки.

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

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

#include <Windows.h>

int main()
{
    HANDLE readyEvent = CreateEvent(NULL, TRUE, FALSE, "ready");
    if (!readyEvent) return -1;

    HANDLE mutex = CreateMutex(NULL, FALSE, "name");
    if (!mutex) return -1;

    while(true)
    {
        if (WaitForSingleObject(readyEvent, 1000) == WAIT_OBJECT_0)
        {
            if (WaitForSingleObject(mutex, 1000) == WAIT_OBJECT_0)
            {
                // process as needed...
                ResetEvent(readyEvent);
                ReleaseMutex(mutex);
            }
        }
    }

    return 0;
}

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

#include <Windows.h>

int main()
{
    HANDLE mutex = CreateMutex(NULL, FALSE, "name");
    if (!mutex) return -1;

    while(true)
    {
        if (WaitForSingleObject(mutex, 1000) == WAIT_OBJECT_0)
        {
            if (ready)
            {
                // process as needed...
                ready = false;
            }
            ReleaseMutex(mutex);
        }
    }

    return 0;
}

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

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

#include <Windows.h>

int main()
{
    HANDLE mutex = CreateMutex(NULL, 0, "name");
    if (!mutex) return -1;

    while(true)
    {
        if (WaitForSingleObject(mutex, 1000) == WAIT_OBJECT_0)
        {
            // check data for changes
            // process new data as needed
            // cache results for next time...
            ReleaseMutex(mutex);
        }
    }

    return 0;
}
  • 0
    так что я слышу, я не могу избежать смены продюсера, если я хочу, чтобы это не было сделано глупо. понял. Как вы имеете в виду использовать семафор вместо этого для поддержки нескольких клиентов с событиями (если я меняю производителя, я могу также сделать это правильно)?
0

Tricky. Я собираюсь ответить на основной вопрос: когда написана память?

Это можно наблюдать с помощью четырехэтапного решения:

  1. Внедрить DLL в наблюдаемый процесс
  2. Добавить векторный обработчик исключений для STATUS_GUARD_PAGE_VIOLATION
  3. Установите бит защитной страницы в диапазоне памяти 2 МБ (обнаружение, что это может быть проблемой)
  4. Из вектора обработчика исключений сообщите об этом процессе и восстановите бит защиты (он один раз)

Вам может понадобиться только одна страница защиты, если изображение всегда полностью перезаписано.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню