Разблокировать поток из другого процесса в С++

Я программирую модуль межпроцессного взаимодействия (процесс A и процесс B).

Есть ли способ, которым коммуникационный поток в B может запуститься (разблокироваться), как только процесс A завершит определенное действие, я имею в виду, что B не будет выполнять какой-либо опрос, а B не будет ждать слишком долго после того, как A завершит свое действие?

Какие концепции/модели/шаблоны проектирования регулируют эти вопросы? (Что-то более точное, чем межпроцессная синхронизация). Какие библиотеки/методы вы рекомендуете?

Спасибо.

Редактировать: я ищу методы, подходящие для каждой из трех основных операционных систем: Ms Windows, Apple Mac OS X, GNU/Linux.


person moala    schedule 05.08.2009    source источник
comment
Я неправильно понял вопрос, думая, что это проблема между потоками. Я добавил информацию о том, как это сделать между процессами, надеюсь, это поможет   -  person Hasturkun    schedule 17.08.2009


Ответы (5)


Это довольно сложная работа:

Для ОС Unix вы можете использовать:

  • условие pthread и мьютекс с аргументом setpshared.

    Примечание: он хорошо поддерживается в Linux 2.6, Solaris, но не поддерживает FreeBSD и Cygwin (не знаю о Mac OS X).

  • Для Unix вы также можете использовать именованные семафоры, но я не знаю их уровня поддержки.

  • Для Windows есть некоторые события...

Это тяжелая работа, особенно для IPC...

Поэтому, если вы хотите что-то переносимое, я бы посоветовал взглянуть на Boost.Interprocess, в котором есть условия и мьютексы...

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

На что следует обратить внимание при работе с Boost.Interprocess

Внимательно проверьте уровень поддержки для каждой ОС Unix, с которой вам нужно работать, потому что Boost.Interprosess использует функции pthread_*, которые не всегда поддерживаются... и затем возвращается к эмуляции - проверьте качество такой эмуляции

Кроме того, проверьте, как этот материал работает в Windows - насколько я знаю, в Win32 API нет мьютексов "в общей памяти", должны использоваться обычно именованные объекты, поэтому проверьте, что поддерживается и как.

person Artyom    schedule 17.08.2009
comment
Просто отсутствует дополнительное упоминание о boost::interprocess::interprocess_semaphore - person moala; 22.02.2010

EDIT: я ошибочно подумал, что вам нужна синхронизация между потоками, пересмотрено для IPC

Я думаю, вам нужно что-то вроде ожидаемых событий.

В Windows для создания (или получить существующее) именованное событие с автоматическим сбросом.

Когда процесс A завершит обработку, он должен вызвать SetEvent(), тогда как процесс B должен вызвать WaitForSingleObject() для спать до завершения (или таймаута).

В качестве альтернативы вы можете использовать семафоры, созданные CreateSemaphore(). , инициализируется значением 0. Процесс A сигнализирует о завершении, вызывая ReleaseSemaphore()< /a>, а процесс B снова использует WaitForSingleObject() ждать завершения.

В Linux и OS X вы можете использовать семафоры с аналогичным эффектом. используйте sem_open() для создания именованного семафор с 0 в качестве начального значения.

Когда процесс A завершится, он должен вызвать sem_post()< /a> для увеличения семафора, а процесс B должен вызывать sem_wait() в спящий режим до завершения.

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


Я думаю, что условные переменные подходят для того, что вы пытаетесь сделать, вот пример, который будет работать в Linux и OSX.

#include <pthread.h>
/* no error checking, quick and dirty sample */
pthread_mutex_t g_mutex;
pthread_cond_t g_cond;
int a_done = 0;

void init(void)
{
    pthread_mutex_init(&g_mutex, NULL);
    pthread_cond_init(&g_cond, NULL);
}

void thread_a(void *arg)
{
    /* do something here... */
    pthread_mutex_lock(&g_mutex);
    a_done = 1;
    pthread_cond_signal(&g_cond);
    pthread_mutex_unlock(&g_mutex);
}

void thread_b(void *arg)
{
    /* wait for a to complete */
    pthread_mutex_lock(&g_mutex);
    while (!a_done)
        pthread_cond_wait(&g_cond, &g_mutex);
    a_done = 0;
    pthread_mutex_unlock(&g_mutex);
}

В Windows вы можете использовать pthreads-win32 или собственные переменные условия в Vista, см. переменные условия MSDN для получения дополнительной информации.

Использованная литература:

person Hasturkun    schedule 05.08.2009
comment
Ответ не касается межпроцессной части. Я не использовал интенсивно pthread-win32, проверьте проблемы совместимости - person neuro; 10.08.2009
comment
ах, я прочитал это как проблему между потоками. позже поправлю ответ - person Hasturkun; 10.08.2009

Если ваша ОС поддерживает сигналы, вы можете разблокировать мьютекс из обработчика сигналов и отправить сигнал из процесса A, как только закончите задачу.

Процесс B будет ожидать мьютекса или другого инструмента синхронизации, а A будет работать над чем угодно, а затем, когда закончит, пошлет, например, сигнал USR1, а обработчик USR1 в процессе B разблокирует соответствующий инструмент синхронизации.

person Arkaitz Jimenez    schedule 05.08.2009
comment
Кажется, это POSIX; вы видели, что адаптировано под винду? - person moala; 05.08.2009
comment
Не уверен, что вы можете правильно использовать сигналы в Windows, но я знаю, что у вас есть другие варианты, поскольку события Windows их не использовали. - person Arkaitz Jimenez; 05.08.2009

Наиболее распространенным является использование select()/poll(). Оба могут проверять несколько файловых дескрипторов, если есть доступный ввод. Оба получают параметр тайм-аута - это предотвратит ожидание занятости, которое может потреблять 100% ресурсов ЦП. Это очень подходящее решение для малых/средних приложений.

Другой подход — сделать опрос в отдельном потоке.

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

person dimba    schedule 05.08.2009
comment
Спасибо за ваш ответ, но я имел в виду без опроса B. Может быть, select() более подходит? - person moala; 05.08.2009
comment
Единственный способ, которым я могу это сделать, это сигнализация (signal() в Linux), но по моему опыту это решение не подходит для высокой нагрузки. В Linux сигнал также прерывает системные вызовы (ошибка EINTR), что излишне усложняет вашу программу. Вызов select()/poll() с нулевым временем ожидания просто проверит, есть ли что прочитать. После этого вы можете продолжить выполнение других задач. - person dimba; 05.08.2009

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

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

Для переносимости используйте портативную библиотеку сокетов, например boost или ptypes или что-то подобное.

person neuro    schedule 10.08.2009