Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Limiting a number of processes/instances
Forum Updated to NodeBB v4.3 + New Features

Limiting a number of processes/instances

Scheduled Pinned Locked Moved Unsolved C++ Gurus
limit processes
5 Posts 4 Posters 1.7k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    koahnig
    wrote on last edited by koahnig
    #1

    Hi there,

    I have a requirement similar to singleton, but limiting the number of instances to a specific number. In general those different instances are running as different processes on the same machine.

    The current implementation is based on QSharedMemory

    In the shared memory basically time tags are stored. One time tag per process for its "start", "sign of still living" and when the "process ended". The "sign of still living" may be screened and entries may be removed after some expiration time. Also entries marked as ended may be removed from table.

    Obviously the design has some flaws. A crashing application cannot mark its entry with "process ended". Also a process with some blockage for a while cannot send a "sign of still living" may be eliminated after its expiration and suddenly the entry may used by two processes.

    I appreciate some alternative designs or extensions. Any ideas around?

    Vote the answer(s) that helped you to solve your issue(s)

    J.HilkJ K 2 Replies Last reply
    0
    • K koahnig

      Hi there,

      I have a requirement similar to singleton, but limiting the number of instances to a specific number. In general those different instances are running as different processes on the same machine.

      The current implementation is based on QSharedMemory

      In the shared memory basically time tags are stored. One time tag per process for its "start", "sign of still living" and when the "process ended". The "sign of still living" may be screened and entries may be removed after some expiration time. Also entries marked as ended may be removed from table.

      Obviously the design has some flaws. A crashing application cannot mark its entry with "process ended". Also a process with some blockage for a while cannot send a "sign of still living" may be eliminated after its expiration and suddenly the entry may used by two processes.

      I appreciate some alternative designs or extensions. Any ideas around?

      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by
      #2

      @koahnig mmh, maybe creating an "Instance Manager" might help. It follows what you do so far with QSharedMemory / RemoteObject.
      But you could implement some kind of heartbeat-functionality, the manager uses to communicate with the instances.

      If a timeout occurs the process is marked tor termination, and a backup process is started.


      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      K 1 Reply Last reply
      0
      • J.HilkJ J.Hilk

        @koahnig mmh, maybe creating an "Instance Manager" might help. It follows what you do so far with QSharedMemory / RemoteObject.
        But you could implement some kind of heartbeat-functionality, the manager uses to communicate with the instances.

        If a timeout occurs the process is marked tor termination, and a backup process is started.

        K Offline
        K Offline
        koahnig
        wrote on last edited by
        #3

        @J.Hilk

        Thanks for suggestion.

        I thought also about some instance manager. Basically I have one already implemented and I was thinking about extending it.

        It is holding basically a bunch of QTcpSockets. Each process is connecting with a QTcpSocket and it checks once in a while if the socket is still connected. When the socket is dropped, the instance will be stopped.

        This could be combined with the QSharedMemory solution. Wasn't sure if I am thinking too complex.

        Vote the answer(s) that helped you to solve your issue(s)

        kshegunovK 1 Reply Last reply
        0
        • K koahnig

          Hi there,

          I have a requirement similar to singleton, but limiting the number of instances to a specific number. In general those different instances are running as different processes on the same machine.

          The current implementation is based on QSharedMemory

          In the shared memory basically time tags are stored. One time tag per process for its "start", "sign of still living" and when the "process ended". The "sign of still living" may be screened and entries may be removed after some expiration time. Also entries marked as ended may be removed from table.

          Obviously the design has some flaws. A crashing application cannot mark its entry with "process ended". Also a process with some blockage for a while cannot send a "sign of still living" may be eliminated after its expiration and suddenly the entry may used by two processes.

          I appreciate some alternative designs or extensions. Any ideas around?

          K Offline
          K Offline
          Konstantin Tokarev
          wrote on last edited by
          #4

          @koahnig See https://github.com/itay-grudev/SingleApplication which is based on old QtSingleApplication solution. It implements limit for case N = 1, but you can reuse idea and make it more generic

          1 Reply Last reply
          1
          • K koahnig

            @J.Hilk

            Thanks for suggestion.

            I thought also about some instance manager. Basically I have one already implemented and I was thinking about extending it.

            It is holding basically a bunch of QTcpSockets. Each process is connecting with a QTcpSocket and it checks once in a while if the socket is still connected. When the socket is dropped, the instance will be stopped.

            This could be combined with the QSharedMemory solution. Wasn't sure if I am thinking too complex.

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by kshegunov
            #5

            You could try something along these lines:

            #include <QThread>
            #include <QSystemSemaphore>
            #include <QSemaphore>
            
            class ProcessCounter
            {
                class ProcessCounterThread : public QThread
                {
                public:
                    ProcessCounterThread(qint64 timeout, QSystemSemaphore &);
                    void release();
                    void cancel();
                    bool success() const;
            
                protected:
                    void run() override;
            
                private:
                    bool acquired;
                    qint64 maxWaitTime;
                    QSemaphore semaphore;
                    QSystemSemaphore & systemSemaphore;
                };
            
            public:
                ProcessCounter(const QString & key, int count, qint64 timeout = 1000);
                ~ProcessCounter();
            
                bool acquired() const;
            
            private:
                QSystemSemaphore semaphore;
                ProcessCounterThread thread;
            };
            
            inline ProcessCounter::ProcessCounterThread::ProcessCounterThread(qint64 timeout, QSystemSemaphore & sem)
                : acquired(false), maxWaitTime(timeout), systemSemaphore(sem)
            {
            }
            
            inline bool ProcessCounter::ProcessCounterThread::success() const
            {
                return acquired;
            }
            
            inline void ProcessCounter::ProcessCounterThread::release()
            {
                semaphore.release();
            }
            
            inline void ProcessCounter::ProcessCounterThread::cancel()
            {
                semaphore.release();
                wait();
            
                acquired = false;
            }
            
            void ProcessCounter::ProcessCounterThread::run()
            {
                acquired = semaphore.tryAcquire(1, maxWaitTime);
                if (!acquired)
                    systemSemaphore.release();
            }
            
            ProcessCounter::ProcessCounter(const QString & key, int count, qint64 timeout)
                : semaphore(key, count), thread(timeout, semaphore)
            {
                thread.start();
                if (!semaphore.acquire())  {
                    thread.cancel();
                    // ... Error handling
                    return;
                }
            
                thread.wait();      // Wait a bit hoping for the global resource to become available
            }
            
            ProcessCounter::~ProcessCounter()
            {
                if (thread.success())
                    semaphore.release();    // We had our global semaphore acquired, now it's time to release it
            }
            
            inline bool ProcessCounter::acquired() const
            {
                return thread.success();
            }
            

            Usage on the stack (as expected):

            static const int maxProcesses = 20;
            static const qint64 timeout = 1000;
            static const QString key = QStringLiteral("KeyForTheGlobalSemaphore");
            
            int main(int argc, char ** argv)
            {
                QApplication app(argc, argv);
            
                ProcessCounter counter(key, maxProcesses, timeout);
                if (!counter.acquired())
                    return 0; // Not allowed, too many processes running already
            
                return QApplication::exec();
            }
            

            Note you'd need to handle SIGSEGV and possibly other signals manually and you shouldn't call ::exit at all, because it will not run the ProcessCounter's destructor, meaning the global semaphore won't be released. Graceful shutdown is paramount here.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved