Создание глобального именованного счетчика, разделяемого между процессами - PullRequest
1 голос
/ 23 ноября 2010

Как я могу создать глобальное значение счетчика, которое может совместно использоваться несколькими процессами в c ++?Что мне нужно, так это способ «сделать недействительными» сразу несколько процессов, сигнализируя им о необходимости выполнить какую-либо операцию (например, чтение из файла).Все процессы будут непрерывно опрашивать (каждые 10 мс) текущее значение счетчика и сравнивать его с внутренним сохраненным последним значением.Несовпадение значений может указывать на необходимость некоторой работы.

Редактировать: Кстати, мои процессы выполняются как разные .exe: s, а не созданы из какого-либо родительского процесса.Операционная система Windows.

Ответы [ 7 ]

2 голосов
/ 23 ноября 2010

А как насчет именованного семафора? Posix поддерживает это, не уверен насчет windows.

1 голос
/ 23 ноября 2010

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

То, как я читаю ваш вопрос, есть несколько читателей, писатель не знает (или не заботится по большей части), сколько читателей одновременно, но хочет уведомить читателей, что для чтения доступно что-то новое. ,

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

MS Windows:

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

Подробнее см. http://www.codeproject.com/KB/DLL/data_seg_share.aspx.

// Note: Be very wary of using anything other than primitive types here!
#pragma data_seg(".mysegmentname") 
HWND hWnd = NULL; 
LONG nVersion = -1;
#pragma data_seg()
#pragma comment(linker, "/section:.mysegmentname,rws")

IPC - COM
Сделайте ваше главное приложение ком-сервисом, где работники смогут регистрироваться для событий, выкладывать изменения в каждый приемник событий.

МПК - двойные события
Предполагая, что 1 цикл чтения намного меньше времени между событиями записи. создайте 2 события ручного сброса, в любое время будет сигнализировано не более 1 из этих событий, чередование между событиями. сигнализация немедленно освободит всех читателей, и после завершения они будут ждать альтернативного события.

0 голосов
/ 16 декабря 2010

Нашел одно решение для отслеживания изменений в папке (с помощью event_trigger -event) и чтения дополнительной информации о событии из файла:

HANDLE event_trigger;
__int64 event_last_time;
vector<string> event_info_args;
string event_info_file = "event_info.ini";

// On init
event_trigger = FindFirstChangeNotification(".", false, FILE_NOTIFY_CHANGE_LAST_WRITE);
event_last_time = stat_mtime_force("event_info.ini");

// On tick
if (WaitForSingleObject(event_trigger, 0)==0)
{
    ResetEventTrigger(event_trigger);

    if (stat_mtime_changed("event_info.ini", event_last_time))
    {
        FILE* file = fopen_force("event_info.ini");

        char buf[4096];
        assert(fgets(buf, sizeof(buf), file));
        split(buf, event_info_args, "\t\r\n");
        fclose(file);

        // Process event_info_args here...

        HWND wnd = ...;
        InvalidateRect(wnd,0,false);
    }
}

// On event invokation
FILE* file = fopen("event_info.ini", "wt");
assert(file);
fprintf(file,"%s\t%s\t%d\n",
    "par1", "par2", 1234);
fclose(file);

stat_mtime_changed("event_info.ini", event_last_time);


// Helper functions:
void ResetEventTrigger()
{
    do
    {
        FindNextChangeNotification(evt);
    }
    while(WaitForSingleObject(evt, 0)==0);
}
FILE* fopen_force(const char* file);
{
    FILE* f = fopen(file, "rt");
    while(!f)
    {
        Sleep(10+(rand()%100));
        f = fopen(f, "rt");
    }
    assert(f);
    return f;
}
__int64 stat_mtime_force(const char* file)
{
    struct stat stats;
    int res = stat(file, &stats);
    if(res!=0)
    {
        FILE* f = fopen(file, "wt");
        fclose(f);
        res = stat(file, &stats);
    }
    assert(res==0);
    return stats.st_mtime;
}
bool stat_mtime_changed(const char* file, __int64& time);
{
    __int64 newTime = stat_mtime(file);
    if (newTime - time > 0)
    {
        time = newTime;
        return true;
    }
    return false;
}
0 голосов
/ 29 ноября 2010

Поскольку имя исполняемого файла известно, у меня есть другое решение, которое я реализовал (в C #) в проекте всего несколько дней назад: каждый процесс чтения создает именованное событие "Global \ someuniquestring_% u", в котором% u являетсяэто идентификатор процесса.Если событие сигнализируется, прочитайте файл и выполните работу.Процесс отправителя имеет список дескрипторов событий и устанавливает их активными, если файл изменился, и, таким образом, уведомляет все процессы чтения.Время от времени, например, когда файл изменяется, он должен обновлять список дескрипторов событий:

  • Получить все процессы с именем 'reader.exe' (например)
  • Для каждого процесса получите его идентификатор
  • Откройте дескриптор существующего события «Global \ someuniquestring_% u», если это новый процесс.
  • Закройте все дескрипторы, чтобы больше не запускать процессы.
0 голосов
/ 23 ноября 2010

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

Процесс отправки:

  • Установить событие
  • Сон 10 мс
  • СбросСобытие

Процессы получения:

  • Все ожидающие процессы проходят, когда установлено событие
  • Они читают файл
  • Пусть они спят для20 мс, скажем, не может увидеть одно и то же событие дважды.
  • Подождите снова

Сон (10) на самом деле может занять больше времени, чем Сон (20), но это приводит только к другомуцикл (повторное чтение неизмененного файла).

0 голосов
/ 23 ноября 2010

Если вы работаете в * nix, вы можете заставить процессы читать из именованного канала (или сокетов), а затем написать специальное сообщение, чтобы сообщить другим процессам, что они должны завершить работу.

Производительность IPC: именованный канал против сокета

Альтернатива Windows NAmed Pipes в Linux

0 голосов
/ 23 ноября 2010

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

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

...