How to delete shared memory when ctrl c?

380 Views Asked by At

I write a shm struct as following:

  class ShmWorker {
   public:
    ShmWorker() = default;
    virtual ~ShmWorker() {
      shmdt(m_data);
      shmctl(shmid, IPC_RMID, 0); // here is the problem, if ctrl-c, the shared memory
      // won't be deleted
    }   

   protected:
    key_t get_keyid(const std::string & name) {
      const std::string & s = "./" + name;
      if (access(s.c_str(), F_OK) == -1) { const std::string & s1 = "touch " + s; system(s1.c_str()); }
      key_t semkey = ftok(name.c_str(), 1); 
      CE(semkey == -1, "shm_file:%s not existed\n", s.c_str());
      return semkey;
    }   

    template <typename T>
    void init(const std::string& name, int size) {
      key_t m_key = get_keyid(name);
      shmid = shmget(m_key, 0, 0);  // TODO: check m_key existed
      char * p;
      if (shmid == -1) {
        CE(errno != ENOENT && errno != EINVAL, "errno is %s\n", strerror(errno));
        if (std::is_same_v<T, std::string>) shmid = shmget(m_key, sizeof(Header) + STRING_SIZE * size, 0666 | IPC_CREAT | O_EXCL);
        else shmid = shmget(m_key, sizeof(Header) + sizeof(T) * size, 0666 | IPC_CREAT | O_EXCL);
        CE(shmid == -1, "both connet and create are failed for shm\n")
        printf("creating new shm %s %p\n", name.c_str(), p);
        p = (char*)shmat(shmid, NULL, 0);
        Header h(size, 0);
        memcpy(p, &h, sizeof(Header));
      } else {
        p = (char*)shmat(shmid, 0, 0);
        printf("existed m_data = %p\n", p);
      }
    }
 }

}

as you can see, the deconstructor will detach this shared memory and delete it.

but sometimes i need to ctrl-c to end the process. in that case, the shared memory will not be deleted.

is there any method can delete it safely if no live process linked the shared memory?

or delete it in the next time link?

1

There are 1 best solutions below

0
Swift - Friday Pie On

Ctrl-C and similar keystrokes in some environments are processed by terminal and terminal invokes appropriate actions upon them, e.g. by calling kill. In other cases it's handled by run-time library. You have to handle interrupts.

E.g. in POSIX-compatible (which also includes console MinGW applications on Windows) Ctrl-C can be intercepted as SIGINT signal:

#include <iostream>
#include <thread>
#include <atomic>
#include <signal.h>

std::atomic<int> keepRunning;

void interruptHandler(int signum) {
    // if intercepting several signals, we should do checks here 
    // setting some flag to signal main program to quit running.
    keepRunning = 0;
}

// The "main worker" thread.
void threadFunction() {
    std::cout << "Hello, world!" << std::endl;
    std::cout << "Press Ctrl-C to exit." << std::endl;
    while(keepRunning);

    // calling exit() here would result in terminate call but atexit handlers will be invoked
    std::cout << "Interrupt detected." << std::endl;
}

std::thread *infiniteThread;

void exitHandler() {
    std::cout << "Bye, cruel world." << std::endl;
    delete infiniteThread;
}

int main()
{
     signal(SIGINT, interruptHandler);

     std::atexit(exitHandler);

     keepRunning = 1;
     infiniteThread = new std::thread(threadFunction);
     infiniteThread->join();
}

interruptHandler should do something to cause process end gracefully. Which may include closing files, sockets, freeing other OS-related resources which aren't under normal circumstances by OS specs, calling atexit-handlers. Not all signals can be caught, when OS actually kills the process, it doesn't have that grace time. interruptHandler is called from what is known as signal trampoline, so provoking exceptions there is not recommended. See manpages.

What can be used in handler is limited. In POSIX environment it's not safe to call exit() from signal handler according to the list of safe functions. But _exit() or _Exit() wouldn't call any atexit functions, it would do only init-related cleanup.