Я пытаюсь сказать, когда процесс производителя обращается к общему обоюдному файлу 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.
Вы не сможете избежать изменения производителя, если необходим эффективный обмен. Для этого ваш дизайн имеет фундаментальные недостатки.
Производитель должен иметь возможность сигнализировать потребителю, когда данные готовы к потреблению, и чтобы убедиться, что он не изменяет данные во время потребления. Вы не можете сделать это только с одним мьютексом.
Лучше всего, чтобы производитель установил событие, когда данные готовы, и пользователь перезагрузит событие, когда данные были использованы. Используйте мьютексы только для синхронизации доступа к данным, а не для сигнализации готовности данных.
#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;
}
Tricky. Я собираюсь ответить на основной вопрос: когда написана память?
Это можно наблюдать с помощью четырехэтапного решения:
STATUS_GUARD_PAGE_VIOLATION
Вам может понадобиться только одна страница защиты, если изображение всегда полностью перезаписано.
CreateEvent
), и производитель может установить его, чтобы ваш другой процесс знал, что пора обрабатывать данные.