One instance of C ++ program using boost :: interprocess

I have a console application that I am trying to run only one time at a time. For this I used the boost interprocess shared_memory_object library. See the code snippet below,

  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

      

The point is that the method prevents my application from running more than once at the same time; however, suppose the user stops the execution of the program, then the memory will not be freed, and the next time the user tries to run the program again, it will not be started. Do you have any suggestions?

PS C ++ Console Application, OS: Ubuntu (but a solution that will work on other platforms would be ideal). Thanks you

+3


source to share


2 answers


What you need to do is catch unexpected program terminations and release the shared memory object accordingly. You can catch SIGINT

like this using the signal.h

POSIX header :

#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...

}

      



And you can catch program termination the same way using a function atexit()

. The documentation is here .

+4


source


NOTICE Answer teleported from How to limit the number of running instances in C ++ . It is here because it is addressed to a portable solution using Boost Interprocess and Boost Asio. In detail.

Note that the solution is more general as you can use it to limit instances to a specific maximum, not just 1

On Linux (and possibly other OSes?) You can use the locking idiom (but it is not supported by some filesystems and older kernels).

I would suggest using Interprocess sync objects.

For example, using a Boost Interprocess named semaphore :

#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");
        }
    }
}

      

If you run one copy in the background, the new copies will "refuse" to run ("Oops, second instance") for about 30 seconds.

I have a feeling that it might be easier to reverse the logic here. Mmm. Lemme try it.

some time passes



Heh. It was more difficult than I thought.

The point is, you want to make sure no blocking remains when your application is interrupted or killed. In the interest of sharing portable signal management techniques:

#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";
    }
}

      

There is much that can be explained. Let me know if you are interested.

NOTE . It should be quite obvious that if kill -9

used in your application (forced termination) then all bets are disabled and you will have to either delete the Name Semaphore object or explicitly unblock it ( post()

).

Here's testrun on my system:

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


source







All Articles