linux — один экземпляр программы на C ++, использующий boost :: interprocess

У меня есть консольное приложение, которое я пытаюсь запустить только один раз за раз. Для этого я использовал библиотеку boost interprocess shared_memory_object. Смотрите фрагмент кода ниже,

  boost::scoped_ptr<shared_memory_object> sharedMem;

try
{
sharedMem.reset(
new shared_memory_object(create_only, "shared_memory", read_write));
} catch(...)
{
// executable is already running
cerr << "Another instance of this program is running!" << endl;
return 1;
}

// do something

shared_memory_object::remove("shared_memory");  // remove the shared memory before exiting the application

Дело в том, что этот метод не позволяет моему приложению запускаться более одного раза одновременно; однако давайте предположим, что пользователь останавливает выполнение программы, тогда память не будет освобождена, и в следующий раз, когда пользователь попытается снова запустить программу, она не запустится. У вас есть какие-нибудь предложения ?

Постскриптум Консольное приложение C ++, ОС: Ubuntu (но решение, которое будет работать и на других платформах, было бы идеальным).
Спасибо

3

Решение

Что вам нужно сделать, так это перехватить неожиданные завершения программы и соответственно освободить объект общей памяти. Вы можете поймать SIGINT следующим образом, используя signal.h POSIX заголовок:

#include <signal.h>

void handleSIGINT(int param=0) {
// Reset the shared memory object here
}

int main() {

// Connect the signal handler to SIGINT
signal(SIGINT, handleSIGINT);

// Etc...

}

И вы можете поймать завершение программы таким же образом, используя atexit() функция. Документация Вот.

4

Другие решения

УВЕДОМЛЕНИЕ Ответ телепортирован из Как ограничить количество запущенных экземпляров в C ++. Он здесь, поскольку он детально описывает портативное решение с использованием Boost Interprocess и Boost Asio.

Обратите внимание, что решение является более общим, в том смысле, что вы можете использовать его для ограничения экземпляров до определенного максимума, а не просто 1

В Linux (и, возможно, в других ОС?) Вы можете использовать идиому файла блокировки (но она не поддерживается некоторыми файловыми системами и старыми ядрами).

Я бы предложил использовать межпроцессные объекты синхронизации.

Например, используя Boost Interprocess с именем семафор:

#include <boost/interprocess/sync/named_semaphore.hpp>
#include <boost/thread.hpp>
#include <cassert>

int main()
{
using namespace boost::interprocess;
named_semaphore sem(open_or_create, "ffed38bd-f0fc-4f79-8838-5301c328268c", 0ul);

if (sem.try_wait())
{
std::cout << "Oops, second instance\n";
}
else
{
sem.post();

// feign hard work for 30s
boost::this_thread::sleep_for(boost::chrono::seconds(30));

if (sem.try_wait())
{
sem.remove("ffed38bd-f0fc-4f79-8838-5301c328268c");
}
}
}

Если вы запустите одну копию на заднем плане, новые копии будут «отказываться» запускаться («К сожалению, второй экземпляр») в течение 30 секунд.

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

проходит некоторое время

Хехе. Это было сложнее, чем я думал.

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

#include <boost/interprocess/sync/named_semaphore.hpp>
#include <boost/thread.hpp>
#include <cassert>
#include <boost/asio.hpp>

#define MAX_PROCESS_INSTANCES 3

boost::interprocess::named_semaphore sem(
boost::interprocess::open_or_create,
"4de7ddfe-2bd5-428f-b74d-080970f980be",
MAX_PROCESS_INSTANCES);

// to handle signals:
boost::asio::io_service service;
boost::asio::signal_set sig(service);

int main()
{

if (sem.try_wait())
{
sig.add(SIGINT);
sig.add(SIGTERM);
sig.add(SIGABRT);
sig.async_wait([](boost::system::error_code,int sig){
std::cerr << "Exiting with signal " << sig << "...\n";
sem.post();
});
boost::thread sig_listener([&] { service.run(); });

boost::this_thread::sleep_for(boost::chrono::seconds(3));

service.post([&] { sig.cancel(); });
sig_listener.join();
}
else
{
std::cout << "More than " << MAX_PROCESS_INSTANCES << " instances not allowed\n";
}
}

Там можно многое объяснить. Дайте мне знать, если вы заинтересованы.

НОТА Должно быть совершенно очевидно, что если kill -9 используется в вашем приложении (принудительное завершение), тогда все ставки отключены, и вам придется либо удалить объект Name Semaphore, либо явно разблокировать его (post()).

Вот тестовый прогон в моей системе:

sehe@desktop:/tmp$ (for a in {1..6}; do ./test& done; time wait)
More than 3 instances not allowed
More than 3 instances not allowed
More than 3 instances not allowed
Exiting with signal 0...
Exiting with signal 0...
Exiting with signal 0...

real    0m3.005s
user    0m0.013s
sys 0m0.012s
3

По вопросам рекламы [email protected]