单个C ++程序实例,使用boost :: interprocess

时间:2014-11-12 08:41:12

标签: c++ linux boost interprocess single-instance

我有一个控制台应用程序,我试图让它一次只能运行一次。我使用了boost进程库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

问题是,该方法可以防止我的应用程序同时运行多次;但是,让我们假设用户停止程序运行,然后内存将不会被释放,下次当用户再次尝试运行程序时,它将无法运行。你有什么建议吗?

P.S。 C ++控制台应用程序,操作系统:Ubuntu(但是一个可以在其他平台上运行的解决方案也是完美的)。 谢谢

2 个答案:

答案 0 :(得分:4)

您需要做的是捕获程序的意外终止并相应地释放共享内存对象。您可以使用SIGINT POSIX标题来捕获signal.h,如下所示:

#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()函数以相同的方式捕获程序终止。文档here

答案 1 :(得分:3)

  

通知 How to limit the number of running instances in 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秒。

我觉得在这里扭转逻辑可能更容易。嗯。 Lemme试试。

一段时间过去

鹤鹤。这比我想象的要复杂得多。

问题是,您希望确保在应用程序中断或终止时锁不会保留。为了分享便携式处理信号的技术:

#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(强制终止),则所有投注均已关闭,您必须删除名称信号量对象或明确解锁它(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