УВЕДОМЛЕНИЕ Ответ телепортирован из Как ограничить количество запущенных экземпляров в 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
person
sehe
schedule
12.11.2014
SIGINT
, который вы сможете поймать и обработать, например, для очистки ресурсов, которые в противном случае не освобождаются. - person Some programmer dude   schedule 12.11.2014